├── LICENSE ├── README.md ├── res ├── Setup.json ├── libwnd.png └── mainwnd.png └── src ├── AaxAudioConverter 2.x.sln ├── Audible.json.core ├── Audible.json.core.csproj ├── LibraryResponse.cs ├── LicenseResponse.cs ├── RegistrationResponse.cs ├── Serialization.cs └── Voucher.cs ├── AuxLib.core ├── AffineSynchronizationContext.cs ├── ApplEnv.cs ├── ArgParser.cs ├── AuxLib.core.csproj ├── BigEndianReader.cs ├── BooleanYesNoConverter.cs ├── ChainPunctuation.cs ├── EnumChainTypeConverter.cs ├── EnumConverter.cs ├── EnumUtil.cs ├── ExtensionsSyncContext.cs ├── ExtensionsVarious.cs ├── IInteractionCallback.cs ├── Indent.cs ├── InteractionCallback.cs ├── InteractionMessage.cs ├── Interfaces.cs ├── JsonSerialization.cs ├── LogGuard.cs ├── Logging.cs ├── ProcessHost.cs ├── ProcessList.cs ├── ResourceGuard.cs ├── ResourceManagerEx.cs ├── SettingsManager.cs ├── ShellExecute.cs ├── Singleton.cs ├── SymmetricEncryptor.cs ├── Temp.cs ├── TimeUtil.cs └── crc.cs ├── AuxWin.DialogBox.core ├── AuxWin.DialogBox.core.csproj ├── CbtHook.cs ├── DialogBox.cs ├── Win32API.cs ├── WindowsHook.cs └── WndProcRetHook.cs ├── AuxWin.lib.core ├── AuxWin.lib.core.csproj ├── ExtensionsControl.cs ├── ExtensionsForm.cs ├── InteractionCallbackHandler.cs ├── Interfaces.cs ├── Properties │ ├── Resources.Designer.cs │ └── Resources.resx ├── SimpleWizard.Designer.cs ├── SimpleWizard.cs ├── SimpleWizard.resx ├── SortableBindingList.cs ├── SortableBindingListSuspensible.cs └── SystemMenu.cs ├── AuxWin32Lib.core ├── AuxWin32Lib.core.csproj ├── FileAssociation.cs └── Win32FileIO.cs ├── BooksDatabase.core ├── AudioQuality.cs ├── BooksDatabase.core.csproj ├── BooksDbContext.cs ├── Entities.cs ├── Extensions.cs ├── Interfaces.cs ├── InternalsVisible.cs ├── Migrations │ ├── 20220107145340_InitialCreate.Designer.cs │ ├── 20220107145340_InitialCreate.cs │ ├── 20220119172449_SeriesSeq.Designer.cs │ ├── 20220119172449_SeriesSeq.cs │ ├── 20220122181409_ChapterTree.Designer.cs │ ├── 20220122181409_ChapterTree.cs │ ├── 20220210175323_NullableDeleted.Designer.cs │ ├── 20220210175323_NullableDeleted.cs │ ├── 20220219161122_DownloadQuality.Designer.cs │ ├── 20220219161122_DownloadQuality.cs │ └── BookDbContextModelSnapshot.cs └── enums.cs ├── CommonTypes.lib.core ├── CommonTypes.lib.core.csproj ├── Enums.cs └── Interfaces.cs ├── CommonUtil.lib.core ├── CommonUtil.lib.core.csproj ├── FileEx.cs ├── LogTmpFileMaintenance.cs ├── OnlineUpdate.cs ├── Records.cs ├── Settings.cs ├── ThreadProgress.cs ├── ToStringConverters.cs └── enums.cs ├── Connect.app.gui.core ├── AboutForm.Designer.cs ├── AboutForm.cs ├── AboutForm.resx ├── AppSettings.cs ├── BookLibConnect.odt ├── Connect.app.gui.core.csproj ├── ConversionContext.cs ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── Program.cs ├── ProgressProcessor.cs ├── Properties │ ├── PublishProfiles │ │ └── FolderProfile.pubxml │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ ├── Settings.settings │ └── launchSettings.json ├── Resources │ ├── audio.ico │ └── audio.png ├── UserSettings.cs ├── WaitForm.Designer.cs ├── WaitForm.cs ├── WaitForm.resx ├── WizStepDownload.Designer.cs ├── WizStepDownload.cs ├── WizStepDownload.resx ├── WizStepExport.Designer.cs ├── WizStepExport.cs ├── WizStepExport.resx ├── WizStepHelp.Designer.cs ├── WizStepHelp.cs ├── WizStepHelp.resx ├── WizStepProfile.Designer.cs ├── WizStepProfile.cs ├── WizStepProfile.resx └── appsettings.json ├── Connect.lib.core ├── AaxExporter.cs ├── AccountAlias.cs ├── Anonymizer.cs ├── AudibleApi.cs ├── AudibleClient.cs ├── Authorize.cs ├── BookLibrary.cs ├── Connect.lib.core.csproj ├── ConsoleExternalLoginCallback.cs ├── Delegates.cs ├── DownloadDecryptJob.cs ├── ExtensionsLogging.cs ├── ExtensionsVarious.cs ├── HttpClientEx.cs ├── Interfaces.cs ├── InternalsVisible.cs ├── Localization.cs ├── Login.cs ├── Profile.cs ├── Properties │ ├── Resources.Designer.cs │ └── Resources.resx ├── Records.cs ├── ReducedChoicesDownloadQuality.cs ├── Settings.cs └── enums.cs ├── Connect.ui.lib.core ├── AccountAliasForm.Designer.cs ├── AccountAliasForm.cs ├── AccountAliasForm.resx ├── BookDataSource.cs ├── BookDataSourceBase.cs ├── BookLibDGVControl.Designer.cs ├── BookLibDGVControl.cs ├── BookLibDGVControl.resx ├── BookLibForm.Designer.cs ├── BookLibForm.cs ├── BookLibForm.resx ├── BookPGA.cs ├── Connect.ui.lib.core.csproj ├── ConversionDataSource.cs ├── ConvertDGVControl.Designer.cs ├── ConvertDGVControl.cs ├── ConvertDGVControl.resx ├── DataGridViewEx.cs ├── DataGridViewEx.resx ├── DataSourceBase.cs ├── Events.cs ├── Extensions.cs ├── InternalsVisible.cs ├── ManageProfilesForm.Designer.cs ├── ManageProfilesForm.cs ├── ManageProfilesForm.resx ├── NewProfileForm.Designer.cs ├── NewProfileForm.cs ├── NewProfileForm.resx ├── Properties │ ├── Resources.Designer.cs │ └── Resources.resx ├── Resources │ ├── blank.png │ ├── check.png │ ├── checkGrey.png │ ├── checkMauve.png │ ├── down.png │ ├── downBroken.png │ ├── globe.png │ ├── globeDown.png │ ├── globeFailed.png │ ├── license.png │ ├── licenseDenied.png │ ├── locked.png │ ├── plus.png │ ├── question.png │ ├── redx.png │ ├── right.png │ ├── rightFailed.png │ ├── unlocked.png │ ├── unlocking.png │ └── unlockingFailed.png └── TypeConvertersRM.cs ├── InnoSetup └── BookLibConnect setup.iss ├── PropGridLib.core ├── Attributes.cs ├── BasePropertyGridAdapter.cs ├── Descriptor.cs ├── DynamicProperty.cs ├── PropGridLib.core.csproj ├── PropertyGridExtension.cs └── PropertySorter.cs ├── SystemMgmt.core ├── HardwareId.cs ├── MotherboardInfo.cs └── SystemMgmt.core.csproj └── TreeDecomposition.core ├── AbstractPrimitiveTypes.cs ├── CustomAttributes.cs ├── Enums.cs ├── Interfaces.cs ├── ToStringConverter.cs ├── TreeDecomposition.core.csproj ├── TreeDecomposition.cs ├── TreeDecompositionExtension.cs └── TypeExtension.cs /res/Setup.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Url": "https://github.com/audiamus/BookLibConnect/releases/download/v0.13.1/BookLibConnect-0.13.1-Setup.exe", 4 | "AppName": "BookLibConnect", 5 | "Version": "0.13.1", 6 | "Preview": false, 7 | "Descript": "Standalone Audible downloader and decrypter, companion to AAX Audio Converter", 8 | "Md5": "f3113ee6dfe9bb44604fb34011d45c7d" 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /res/libwnd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/res/libwnd.png -------------------------------------------------------------------------------- /res/mainwnd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/res/mainwnd.png -------------------------------------------------------------------------------- /src/Audible.json.core/Audible.json.core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | core.audiamus.adb.json 6 | audiamus.audiible.json.core 7 | audiamus 8 | Copyright © 2021 - $([System.DateTime]::UtcNow.Year) audiamus ($([System.DateTime]::UtcNow.ToString("s"))) 9 | 0.5.0.0 10 | 0.5.0.0 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Audible.json.core/LicenseResponse.cs: -------------------------------------------------------------------------------- 1 | namespace core.audiamus.adb.json { 2 | 3 | public class LicenseResponse : Serialization { 4 | public ContentLicense content_license { get; set; } 5 | public string[] response_groups { get; set; } 6 | } 7 | 8 | public class MetadataContainer : Serialization { 9 | public ContentMetadata content_metadata { get; set; } 10 | } 11 | 12 | public partial class ContentLicense { 13 | public string acr { get; set; } 14 | public string asin { get; set; } 15 | public ContentMetadata content_metadata { get; set; } 16 | public string drm_type { get; set; } 17 | public string license_id { get; set; } 18 | public string license_response { get; set; } 19 | public string message { get; set; } 20 | public string request_id { get; set; } 21 | public bool? requires_ad_supported_playback { get; set; } 22 | public string status_code { get; set; } 23 | public string voucher_id { get; set; } 24 | 25 | public Voucher voucher { get; set; } 26 | } 27 | 28 | public class ContentMetadata { 29 | public ChapterInfo chapter_info { get; set; } 30 | public ContentReference content_reference { get; set; } 31 | public ContentUrl content_url { get; set; } 32 | public LastPositionHeard last_position_heard { get; set; } 33 | } 34 | 35 | public class ChapterInfo { 36 | public int? brandIntroDurationMs { get; set; } 37 | public int? brandOutroDurationMs { get; set; } 38 | public Chapter[] chapters { get; set; } 39 | public bool? is_accurate { get; set; } 40 | public int? runtime_length_ms { get; set; } 41 | public int? runtime_length_sec { get; set; } 42 | } 43 | 44 | public class Chapter { 45 | public int? length_ms { get; set; } 46 | public int? start_offset_ms { get; set; } 47 | public int? start_offset_sec { get; set; } 48 | public string title { get; set; } 49 | public Chapter[] chapters { get; set; } 50 | } 51 | 52 | public class ContentReference { 53 | public string acr { get; set; } 54 | public string asin { get; set; } 55 | public string content_format { get; set; } 56 | public long? content_size_in_bytes { get; set; } 57 | public string file_version { get; set; } 58 | public string marketplace { get; set; } 59 | public string sku { get; set; } 60 | public string tempo { get; set; } 61 | public string version { get; set; } 62 | } 63 | 64 | public class ContentUrl { 65 | public string offline_url { get; set; } 66 | } 67 | 68 | public class LastPositionHeard { 69 | public string last_updated { get; set; } 70 | public int? position_ms { get; set; } 71 | public string status { get; set; } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Audible.json.core/RegistrationResponse.cs: -------------------------------------------------------------------------------- 1 | namespace core.audiamus.adb.json { 2 | public class RegistrationResponse : Serialization { 3 | public Response response { get; set; } 4 | public string request_id { get; set; } 5 | } 6 | 7 | public class Response { 8 | public Success success { get; set; } 9 | } 10 | 11 | public class Success { 12 | public Extensions extensions { get; set; } 13 | public Tokens tokens { get; set; } 14 | public string customer_id { get; set; } 15 | } 16 | 17 | public class Extensions { 18 | public Device_Info device_info { get; set; } 19 | public Customer_Info customer_info { get; set; } 20 | } 21 | 22 | public class Device_Info { 23 | public string device_name { get; set; } 24 | public string device_serial_number { get; set; } 25 | public string device_type { get; set; } 26 | } 27 | 28 | public class Customer_Info { 29 | public string account_pool { get; set; } 30 | public string user_id { get; set; } 31 | public string home_region { get; set; } 32 | public string name { get; set; } 33 | public string given_name { get; set; } 34 | } 35 | 36 | public class Tokens { 37 | public Website_Cookies[] website_cookies { get; set; } 38 | public Store_Authentication_Cookie store_authentication_cookie { get; set; } 39 | public Mac_Dms mac_dms { get; set; } 40 | public Bearer bearer { get; set; } 41 | } 42 | 43 | public class Store_Authentication_Cookie { 44 | public string cookie { get; set; } 45 | } 46 | 47 | public class Mac_Dms { 48 | public string device_private_key { get; set; } 49 | public string adp_token { get; set; } 50 | } 51 | 52 | public class Bearer { 53 | public string access_token { get; set; } 54 | public string refresh_token { get; set; } 55 | public string expires_in { get; set; } 56 | } 57 | 58 | public class Website_Cookies { 59 | public string Path { get; set; } 60 | public string Secure { get; set; } 61 | public string Value { get; set; } 62 | public string Expires { get; set; } 63 | public string Domain { get; set; } 64 | public string HttpOnly { get; set; } 65 | public string Name { get; set; } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/Audible.json.core/Serialization.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json; 3 | using core.audiamus.aux; 4 | using core.audiamus.aux.ex; 5 | 6 | namespace core.audiamus.adb.json { 7 | public abstract class Serialization { 8 | private static JsonSerializerOptions Options { get; } = JsonExtensions.Options; 9 | 10 | public string Serialize () { 11 | return JsonSerializer.Serialize (this, typeof(T), Options); 12 | } 13 | 14 | public static T Deserialize (string json) { 15 | try { 16 | return JsonSerializer.Deserialize (json, Options); 17 | } catch (Exception exc) { 18 | Logging.Log (1, typeof (Serialization), () => exc.Summary ()); 19 | return default; 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Audible.json.core/Voucher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace core.audiamus.adb.json { 4 | 5 | public class Voucher : Serialization { 6 | public string key { get; set; } 7 | public string iv { get; set; } 8 | public Rule[] rules { get; set; } 9 | } 10 | 11 | public class Rule { 12 | public Parameter[] parameters { get; set; } 13 | public string name { get; set; } 14 | } 15 | 16 | public class Parameter { 17 | public DateTime expireDate { get; set; } 18 | public string type { get; set; } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/AuxLib.core/ApplEnv.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Reflection; 4 | using System.Resources; 5 | using System.Runtime.InteropServices; 6 | using System.Text.RegularExpressions; 7 | 8 | namespace core.audiamus.aux { 9 | public static class ApplEnv { 10 | 11 | static readonly char[] INVALID_CHARS = Path.GetInvalidFileNameChars (); 12 | 13 | public static Version OSVersion { get; } = getOSVersion(); 14 | public static bool Is64BitOperatingSystem => Environment.Is64BitOperatingSystem; 15 | public static bool Is64BitProcess => Environment.Is64BitProcess; 16 | public static int ProcessorCount => Environment.ProcessorCount; 17 | 18 | public static Assembly EntryAssembly { get; } = Assembly.GetEntryAssembly (); 19 | public static Assembly ExecutingAssembly { get; } = Assembly.GetExecutingAssembly (); 20 | 21 | public static Version AssemblyVersion { get; } = EntryAssembly.GetName ().Version; 22 | public static string AssemblyTitle { get; } = 23 | getAttribute ()?.Title ?? Path.GetFileNameWithoutExtension (ExecutingAssembly.Location); 24 | public static string AssemblyProduct { get; } = getAttribute ()?.Product; 25 | public static string AssemblyCopyright { get; } = getAttribute ()?.Copyright; 26 | public static string AssemblyCompany { get; } = getAttribute ()?.Company; 27 | public static string NeutralCultureName { get; } = getAttribute ()?.CultureName; 28 | 29 | public static string AssemblyGuid { get; } = getAttribute ()?.Value; 30 | 31 | public static string ApplName { get; } = EntryAssembly.GetName ().Name; 32 | public static string ApplDirectory { get; } = AppContext.BaseDirectory; 33 | public static string LocalDirectoryRoot { get; } = Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData); 34 | public static string LocalCompanyDirectory { get; } = Path.Combine (LocalDirectoryRoot, getCompanyFileName()); 35 | public static string LocalApplDirectory { get; } = Path.Combine (LocalCompanyDirectory, ApplName); 36 | public static string SettingsDirectory { get; } = Path.Combine (LocalApplDirectory, "settings"); 37 | public static string TempDirectory { get; } = Path.Combine (LocalApplDirectory, "tmp"); 38 | public static string LogDirectory { get; } = Path.Combine (LocalApplDirectory, "log"); 39 | public static string UserName { get; } = Environment.UserName; 40 | public static string UserDirectoryRoot { get; } = Environment.GetFolderPath (Environment.SpecialFolder.UserProfile); 41 | 42 | private static T getAttribute () where T : Attribute { 43 | object[] attributes = EntryAssembly.GetCustomAttributes (typeof (T), false); 44 | if (attributes.Length == 0) 45 | return null; 46 | return attributes[0] as T; 47 | } 48 | 49 | 50 | private static string getCompanyFileName () { 51 | string company = AssemblyCompany; 52 | if (string.IsNullOrEmpty (company)) 53 | company = "misc"; 54 | if (company.IndexOfAny (INVALID_CHARS) >= 0) 55 | foreach (char c in INVALID_CHARS) 56 | company.Replace (c, ' '); 57 | company = company.Replace (' ', '_'); 58 | return company; 59 | } 60 | 61 | 62 | private static Version getOSVersion () { 63 | const string REGEX = @"\s([0-9.]+)"; 64 | string os = RuntimeInformation.OSDescription; 65 | var regex = new Regex (REGEX); 66 | var match = regex.Match (os); 67 | if (!match.Success) 68 | return new Version (); 69 | string osvers = match.Groups[1].Value; 70 | try { 71 | return new Version (osvers); 72 | } catch (Exception) { 73 | return new Version (); 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/AuxLib.core/AuxLib.core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | core.audiamus.aux 6 | audiamus.aux.core 7 | audiamus 8 | 2.2.0.0 9 | 2.2.0.0 10 | Copyright © 2019 - $([System.DateTime]::UtcNow.Year) audiamus ($([System.DateTime]::UtcNow.ToString("s"))) 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/AuxLib.core/BigEndianReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace core.audiamus.aux.ex { 5 | public static class BigEndianReader { 6 | // Note this MODIFIES THE GIVEN ARRAY then returns a reference to the modified array. 7 | public static byte[] Reverse (this byte[] b) { 8 | Array.Reverse (b); 9 | return b; 10 | } 11 | 12 | public static UInt16 ReadUInt16BE (this BinaryReader binRdr) { 13 | return BitConverter.ToUInt16 (binRdr.ReadBytesRequired (sizeof (UInt16)).Reverse (), 0); 14 | } 15 | 16 | public static Int16 ReadInt16BE (this BinaryReader binRdr) { 17 | return BitConverter.ToInt16 (binRdr.ReadBytesRequired (sizeof (Int16)).Reverse (), 0); 18 | } 19 | 20 | public static UInt32 ReadUInt32BE (this BinaryReader binRdr) { 21 | return BitConverter.ToUInt32 (binRdr.ReadBytesRequired (sizeof (UInt32)).Reverse (), 0); 22 | } 23 | 24 | public static Int32 ReadInt32BE (this BinaryReader binRdr) { 25 | return BitConverter.ToInt32 (binRdr.ReadBytesRequired (sizeof (Int32)).Reverse (), 0); 26 | } 27 | 28 | public static UInt64 ReadUInt64BE (this BinaryReader binRdr) { 29 | return BitConverter.ToUInt64 (binRdr.ReadBytesRequired (sizeof (UInt64)).Reverse (), 0); 30 | } 31 | 32 | public static Int64 ReadInt64BE (this BinaryReader binRdr) { 33 | return BitConverter.ToInt64 (binRdr.ReadBytesRequired (sizeof (Int64)).Reverse (), 0); 34 | } 35 | 36 | public static byte[] ReadBytesRequired (this BinaryReader binRdr, int byteCount) { 37 | var result = binRdr.ReadBytes (byteCount); 38 | 39 | if (result.Length != byteCount) 40 | throw new EndOfStreamException (string.Format ("{0} bytes required from stream, but only {1} returned.", byteCount, result.Length)); 41 | 42 | return result; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/AuxLib.core/BooleanYesNoConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Diagnostics; 5 | using System.Globalization; 6 | using System.Resources; 7 | using core.audiamus.aux.ex; 8 | 9 | namespace core.audiamus.aux { 10 | public class BooleanYesNoConverter : BooleanConverter { 11 | 12 | const string TRUE = "Yes"; 13 | const string FALSE = "No"; 14 | 15 | private ResourceManager _resourceManager; 16 | 17 | protected ResourceManager ResourceManager { 18 | get => _resourceManager; 19 | set 20 | { 21 | _resourceManager = value; 22 | initReverseLookup (); 23 | } 24 | } 25 | 26 | Dictionary _reverseLookup; 27 | 28 | public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType) { 29 | if (destinationType != typeof (string)) 30 | return base.CanConvertTo (context, destinationType); 31 | else 32 | return true; 33 | } 34 | 35 | 36 | public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { 37 | #if TRACE && EXTRA 38 | Log.WriteLine ($"{nameof (ConvertTo)}: \"{value}\", from: {value.GetType ().Name}, to: {destinationType.Name}"); 39 | #endif 40 | switch (value) { 41 | default: 42 | return base.ConvertTo (context, culture, value, destinationType); 43 | case bool val: 44 | return toDisplayString (val); 45 | } 46 | } 47 | 48 | public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value) { 49 | #if TRACE && EXTRA 50 | Log.WriteLine ($"{nameof (ConvertFrom)}: \"{value}\", from: {value.GetType ().Name}"); 51 | #endif 52 | if (!(_reverseLookup is null)) { 53 | if (value is string s) { 54 | bool succ = _reverseLookup.TryGetValue (s, out bool b); 55 | if (succ) 56 | return b; 57 | } 58 | } 59 | return base.ConvertFrom (context, culture, value); 60 | 61 | } 62 | 63 | private string toDisplayString (bool value) { 64 | string s = value ? TRUE : FALSE; 65 | return ResourceManager.GetStringEx (s); 66 | } 67 | 68 | private void initReverseLookup () { 69 | _reverseLookup = new Dictionary (); 70 | initReverseLookup (false); 71 | initReverseLookup (true); 72 | } 73 | 74 | private void initReverseLookup (bool value) => _reverseLookup.Add (toDisplayString (value), value); 75 | 76 | } 77 | 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/AuxLib.core/ChainPunctuation.cs: -------------------------------------------------------------------------------- 1 | namespace core.audiamus.aux { 2 | public interface IChainPunctuation { 3 | string Prefix { get; } 4 | string Suffix { get; } 5 | string[] Infix { get; } 6 | //string[] Punctuation { get; } 7 | } 8 | 9 | public abstract class ChainPunctuation : IChainPunctuation { 10 | public abstract string Prefix { get; } 11 | public abstract string Suffix { get; } 12 | public abstract string[] Infix { get; } 13 | //public string[] Punctuation => new string[] { Prefix, Suffix, Infix }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/AuxLib.core/EnumConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Diagnostics; 5 | using System.Globalization; 6 | using System.Linq; 7 | using System.Resources; 8 | using core.audiamus.aux.ex; 9 | using static core.audiamus.aux.EnumUtil; 10 | 11 | namespace core.audiamus.aux { 12 | 13 | public class EnumConverter : TypeConverter 14 | where TEnum : struct, Enum 15 | { 16 | 17 | protected IList Values { get; } 18 | 19 | private ResourceManager _resourceManager; 20 | 21 | protected ResourceManager ResourceManager { 22 | get => _resourceManager; 23 | set 24 | { 25 | _resourceManager = value; 26 | initReverseLookup (); 27 | } 28 | } 29 | 30 | Dictionary _reverseLookup; 31 | 32 | public EnumConverter () { 33 | Values = GetValues ().ToArray (); 34 | } 35 | 36 | public override bool GetStandardValuesSupported (ITypeDescriptorContext context) => true; 37 | 38 | public override StandardValuesCollection GetStandardValues (ITypeDescriptorContext context) { 39 | StandardValuesCollection svc = new StandardValuesCollection (Values.ToArray()); 40 | return svc; 41 | } 42 | 43 | 44 | public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType) { 45 | if (destinationType != typeof (string)) 46 | return base.CanConvertTo (context, destinationType); 47 | else 48 | return true; 49 | } 50 | 51 | public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType) { 52 | if (sourceType != typeof (string)) 53 | return base.CanConvertFrom (context, sourceType); 54 | else 55 | return true; 56 | } 57 | 58 | 59 | public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { 60 | #if TRACE && EXTRA 61 | Trace.WriteLine ($"{nameof (ConvertTo)}: \"{value}\", from: {value.GetType ().Name}, to: {destinationType.Name}"); 62 | #endif 63 | switch (value) { 64 | default: 65 | return base.ConvertTo (context, culture, value, destinationType); 66 | case TEnum enm: 67 | return toDisplayString (enm); 68 | } 69 | } 70 | 71 | public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value) { 72 | #if TRACE && EXTRA 73 | Trace.WriteLine ($"{nameof (ConvertFrom)}: \"{value}\", from: {value.GetType ().Name}"); 74 | #endif 75 | if (!(_reverseLookup is null)) { 76 | if (value is string s) { 77 | bool succ = _reverseLookup.TryGetValue (s, out TEnum e); 78 | if (succ) 79 | return e; 80 | } 81 | } 82 | return base.ConvertFrom (context, culture, value); 83 | 84 | } 85 | 86 | private string toDisplayString (TEnum value) => ResourceManager.GetStringEx (value.ToString ()); 87 | 88 | private void initReverseLookup () { 89 | _reverseLookup = new Dictionary (); 90 | foreach (var v in Values) 91 | _reverseLookup.Add (toDisplayString (v), v); 92 | } 93 | 94 | } 95 | 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/AuxLib.core/EnumUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Resources; 5 | using System.Text; 6 | using core.audiamus.aux.ex; 7 | 8 | namespace core.audiamus.aux { 9 | public static class EnumUtil { 10 | // Note: constraint System.Enum available in C# 7.3 11 | public static IEnumerable GetValues () where T : struct, Enum { 12 | var values = Enum.GetValues (typeof (T)); 13 | return values.Cast ().ToList (); 14 | } 15 | 16 | // Note: constraint System.Enum available in C# 7.3 17 | public static string[] GetStringValues () where T : struct, Enum { 18 | var values = GetValues (); 19 | return values.Select (v => $"<{v}>").ToArray (); 20 | } 21 | 22 | const char USCORE = '_'; 23 | static readonly byte __a = Convert.ToByte ('a'); 24 | 25 | public static string ToDisplayString (this TEnum value, ResourceManager rm) 26 | where TEnum: struct, Enum 27 | where TPunct : class, IChainPunctuation, new() 28 | { 29 | 30 | 31 | var punct = Singleton.Instance; 32 | 33 | string sval = value.ToString (); 34 | 35 | //verbatim ? 36 | if (sval.StartsWith ("_")) { 37 | return rm.GetStringEx (sval.Substring (1)); 38 | } 39 | 40 | string[] parts = sval.Split (USCORE); 41 | 42 | bool noSubstitutes = parts.Select (s => s.Length).Min () > 1; 43 | StringBuilder sb = new StringBuilder (); 44 | if (noSubstitutes) { 45 | for (int i = 0; i < parts.Length; i++) 46 | parts[i] = punct.Prefix + rm.GetStringEx (parts[i]) + punct.Suffix; 47 | foreach (string s in parts) { 48 | if (sb.Length > 0) 49 | sb.Append (punct.Infix?[0]); 50 | sb.Append (s); 51 | } 52 | } else { 53 | for (int i = 0; i < parts.Length; i++) { 54 | if (parts[i].Length > 1) 55 | parts[i] = punct.Prefix + rm.GetStringEx (parts[i]) + punct.Suffix; 56 | else { 57 | byte x = Convert.ToByte (parts[i][0]); 58 | try { 59 | parts[i] = punct.Infix?[x - __a]; 60 | } catch (IndexOutOfRangeException) { 61 | parts[i] = string.Empty; 62 | } 63 | } 64 | } 65 | foreach (string s in parts) 66 | sb.Append (s); 67 | } 68 | return sb.ToString (); 69 | } 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/AuxLib.core/IInteractionCallback.cs: -------------------------------------------------------------------------------- 1 | namespace core.audiamus.aux { 2 | public interface IInteractionCallback { 3 | TResult Interact (T value); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/AuxLib.core/Indent.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace core.audiamus.aux { 4 | /// 5 | /// Automatic indentation, managed as a resource 6 | /// 7 | public class Indent : IResource { 8 | 9 | uint _inc = 2; 10 | uint _offset = 0; 11 | int _indent; 12 | string _output = string.Empty; 13 | 14 | public int Level { get; private set; } 15 | 16 | public Indent () { } 17 | public Indent (uint inc) => this._inc = inc; 18 | public Indent (uint? inc, uint offset) { 19 | this._inc = inc ?? this._inc; 20 | this._offset = offset; 21 | buildString (); 22 | } 23 | 24 | public void Acquire () { 25 | Level++; 26 | _indent += (int)_inc; 27 | buildString (); 28 | } 29 | 30 | public void Release () { 31 | Level--; 32 | _indent -= (int)_inc; 33 | buildString (); 34 | } 35 | 36 | public bool InRange (int level) { 37 | if (level < 0) 38 | return true; 39 | else 40 | return Level <= level; 41 | } 42 | 43 | public override string ToString () => _output; 44 | 45 | public void Write (TextWriter osm) => osm.Write (this); 46 | 47 | private void buildString () => _output = new string (' ', (int)_offset + _indent); 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/AuxLib.core/InteractionCallback.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.Contracts; 3 | using System.Threading; 4 | 5 | namespace core.audiamus.aux { 6 | 7 | 8 | /// 9 | /// Provides an IInteractCallback{T, TResult} that invokes callbacks for interaction on the captured SynchronizationContext. 10 | /// 11 | public class InteractionCallback : IInteractionCallback { 12 | private readonly SynchronizationContext _synchronizationContext; 13 | private readonly Func _handler; 14 | 15 | private static readonly SynchronizationContext DefaultContext = new SynchronizationContext (); 16 | 17 | public InteractionCallback (Func handler) { 18 | _synchronizationContext = SynchronizationContext.Current ?? DefaultContext; 19 | Contract.Assert (_synchronizationContext != null); 20 | if (handler is null) 21 | throw new ArgumentNullException (nameof(handler)); 22 | _handler = handler; 23 | } 24 | 25 | 26 | protected virtual TResult onInteract (T value) { 27 | // If there's no handler, don't bother going through the sync context. 28 | TResult retval = default (TResult); 29 | if (_handler != null) { 30 | // Post the processing to the sync context. 31 | // (If T is a value type, it will get boxed here.) 32 | _synchronizationContext.Send (new SendOrPostCallback ((x) => 33 | { 34 | retval = _handler (value); 35 | }) 36 | , null); 37 | 38 | } 39 | return retval; 40 | } 41 | 42 | TResult IInteractionCallback.Interact(T value) => onInteract (value); 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/AuxLib.core/InteractionMessage.cs: -------------------------------------------------------------------------------- 1 | namespace core.audiamus.aux { 2 | public enum ECallbackType { info, infoCancel, warning, error, errorQuestion, errorQuestion3, question, question3 } 3 | 4 | public record InteractionMessage ( 5 | ECallbackType Type, 6 | string Message 7 | ); 8 | 9 | public record InteractionMessage (ECallbackType Type, string Message, T Custom) : 10 | InteractionMessage (Type, Message); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/AuxLib.core/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace core.audiamus.aux { 4 | public interface IProcessList { 5 | bool Add (Process process); 6 | bool Remove (Process process); 7 | } 8 | 9 | public interface IUserSettings { 10 | } 11 | 12 | public interface IInitSettings { 13 | void Init (); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/AuxLib.core/JsonSerialization.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Text.Encodings.Web; 3 | using System.Text.Json; 4 | using System.Text.Json.Serialization; 5 | using System.Threading.Tasks; 6 | 7 | namespace core.audiamus.aux { 8 | public static class JsonSerialization { 9 | private static readonly JsonSerializerOptions __jsonSerializerOptions = new JsonSerializerOptions { 10 | WriteIndented = true, 11 | ReadCommentHandling = JsonCommentHandling.Skip, 12 | AllowTrailingCommas = true, 13 | Converters ={ 14 | new JsonStringEnumConverter() 15 | }, 16 | Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping 17 | }; 18 | 19 | public static string ToJsonString (this T obj) { 20 | return JsonSerializer.Serialize (obj, __jsonSerializerOptions); 21 | } 22 | 23 | public static void ToJsonFile (this T obj, string path) { 24 | using var fs = new FileStream (path, FileMode.Create); 25 | var task = Task.Run (async () => await JsonSerializer.SerializeAsync (fs, obj, __jsonSerializerOptions)); 26 | task.Wait (); 27 | } 28 | 29 | public static T FromJsonString (this string json) { 30 | return JsonSerializer.Deserialize (json, __jsonSerializerOptions); 31 | } 32 | 33 | public static T FromJsonFile (this string path) { 34 | using var fs = new FileStream (path, FileMode.Open, FileAccess.Read); 35 | Task task = Task.Run (async () => await JsonSerializer.DeserializeAsync (fs, __jsonSerializerOptions)); 36 | return task.Result; 37 | } 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/AuxLib.core/LogGuard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace core.audiamus.aux { 5 | 6 | public class LogGuard : IDisposable { 7 | 8 | const string IN = ">>> "; 9 | const string OUT = "<<< "; 10 | readonly uint _level; 11 | readonly Func _func; 12 | readonly string _msg; 13 | readonly string _method; 14 | readonly object _caller; 15 | readonly Type _type; 16 | bool _isDispose; 17 | 18 | public LogGuard (uint level, Type type, Func func, [CallerMemberName] string method = null) { 19 | _level = level; 20 | _type = type; 21 | _func = func; 22 | _method = method; 23 | Logging.Log (level, type, getFuncMsg, method); 24 | } 25 | 26 | public LogGuard (uint level, object caller, Func func, [CallerMemberName] string method = null) { 27 | _level = level; 28 | _caller = caller; 29 | _func = func; 30 | _method = method; 31 | Logging.Log (level, caller, getFuncMsg, method); 32 | } 33 | 34 | public LogGuard (uint level, Type type, string msg, [CallerMemberName] string method = null) { 35 | _level = level; 36 | _type = type; 37 | _msg = msg; 38 | _method = method; 39 | Logging.Log (level, type, getMsg, method); 40 | } 41 | 42 | public LogGuard (uint level, object caller, string msg, [CallerMemberName] string method = null) { 43 | _level = level; 44 | _caller = caller; 45 | _msg = msg; 46 | _method = method; 47 | Logging.Log (level, caller, getMsg (), method); 48 | } 49 | 50 | public LogGuard (uint level, Type type, [CallerMemberName] string method = null) { 51 | _level = level; 52 | _type = type; 53 | _method = method; 54 | Logging.Log (level, type, () => IN, method); 55 | } 56 | 57 | public LogGuard (uint level, object caller, [CallerMemberName] string method = null) { 58 | _level = level; 59 | _caller = caller; 60 | _method = method; 61 | Logging.Log (level, caller, () => IN, method); 62 | } 63 | 64 | public void Dispose () { 65 | _isDispose = true; 66 | if (_type is null) { 67 | if (_func is null) { 68 | if (_msg is null) 69 | Logging.Log (_level, _caller, () => OUT, _method); 70 | else 71 | Logging.Log (_level, _caller, getMsg (), _method); 72 | } else 73 | Logging.Log (_level, _caller, getFuncMsg, _method); 74 | } else if (_type is not null) { 75 | if (_func is null) { 76 | if (_msg is null) 77 | Logging.Log (_level, _type, () => OUT, _method); 78 | else 79 | Logging.Log (_level, _type, getMsg (), _method); 80 | } else 81 | Logging.Log (_level, _type, getFuncMsg, _method); 82 | } 83 | } 84 | 85 | private string getFuncMsg () { 86 | string prefix = _isDispose ? OUT : IN; 87 | return prefix + _func?.Invoke (); 88 | } 89 | 90 | private string getMsg () { 91 | string prefix = _isDispose ? OUT : IN; 92 | return prefix + _msg; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/AuxLib.core/ProcessHost.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Text; 5 | 6 | namespace core.audiamus.aux { 7 | public class ProcessHost { 8 | 9 | protected Process Process { get; private set; } 10 | 11 | /// 12 | /// Executes a process and passes its command-line output back after the process has exited 13 | /// 14 | protected string runProcess ( 15 | string exePath, string parameters, 16 | bool getStdErrorNotOutput = false, 17 | DataReceivedEventHandler eventHandler = null) 18 | { 19 | 20 | if (!File.Exists (exePath)) 21 | return null; 22 | 23 | string result = String.Empty; 24 | bool async = eventHandler != null; 25 | 26 | using (Process p = new Process ()) { 27 | p.StartInfo.UseShellExecute = false; 28 | p.StartInfo.CreateNoWindow = true; 29 | p.StartInfo.FileName = exePath; 30 | p.StartInfo.Arguments = parameters; 31 | 32 | if (getStdErrorNotOutput) 33 | p.StartInfo.RedirectStandardError = true; 34 | else 35 | p.StartInfo.RedirectStandardOutput = true; 36 | p.StartInfo.RedirectStandardInput = true; 37 | 38 | if (async) { 39 | if (getStdErrorNotOutput) 40 | p.ErrorDataReceived += eventHandler; 41 | else 42 | p.OutputDataReceived += eventHandler; 43 | } 44 | 45 | var processOutputStringBuilder = new StringBuilder (); 46 | 47 | p.Start (); 48 | try { 49 | p.PriorityClass = ProcessPriorityClass.BelowNormal; 50 | } catch (Exception) { 51 | } 52 | 53 | Singleton.Instance.Add (p); 54 | Process = p; 55 | 56 | if (async) { 57 | if (getStdErrorNotOutput) 58 | p.BeginErrorReadLine (); 59 | else 60 | p.BeginOutputReadLine (); 61 | } 62 | p.WaitForExit (); 63 | 64 | Singleton.Instance.Remove (p); 65 | Process = null; 66 | 67 | if (!async) { 68 | if (getStdErrorNotOutput) 69 | result = p.StandardError.ReadToEnd (); 70 | else 71 | result = p.StandardOutput.ReadToEnd (); 72 | } else { 73 | if (processOutputStringBuilder.Length > 0) 74 | result = processOutputStringBuilder.ToString (); 75 | } 76 | 77 | } 78 | 79 | return result; 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/AuxLib.core/ProcessList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | 5 | namespace core.audiamus.aux { 6 | public class ProcessList : IDisposable, IProcessList { 7 | 8 | private readonly object _lockable = new object (); 9 | private bool _disposed = false; 10 | 11 | HashSet _processes = new HashSet (); 12 | 13 | public IProcessList Notify { private get; set; } 14 | 15 | public bool Add (Process process) { 16 | Notify?.Add (process); 17 | lock (_lockable) 18 | return _processes.Add (process); 19 | } 20 | 21 | public bool Remove (Process process) { 22 | Notify?.Remove (process); 23 | lock (_lockable) 24 | return _processes.Remove (process); 25 | } 26 | 27 | #region IDisposable Members 28 | 29 | public void Dispose () { 30 | Dispose (true); 31 | GC.SuppressFinalize (this); 32 | } 33 | 34 | #endregion 35 | private void Dispose (bool disposing) { 36 | if (_disposed) 37 | return; 38 | 39 | if (disposing) { 40 | } 41 | 42 | lock (_lockable) 43 | foreach (Process p in _processes) 44 | p.Kill (); 45 | 46 | _disposed = true; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/AuxLib.core/ResourceGuard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace core.audiamus.aux { 4 | /// 5 | /// Implementing and using it with allows 6 | /// RAII behavior within the lifecycle of an instance, beyond ctor/dtor, e.g. for indentation of text. 7 | /// 8 | public interface IResource { 9 | void Acquire (); 10 | void Release (); 11 | } 12 | 13 | /// 14 | /// The "using" statement in C# is syntactic sugar for try {} finally {} and implements the RAII programming idiom. 15 | /// In conjunction with and optionally it can be used 16 | /// for all sorts of dedicated and guaranteed scope entry/exit action. 17 | /// 18 | /// Examples: 19 | /// 20 | /// var resource = new NonIDisposableResource(); 21 | /// using (new ResourceGuard(() => resource.Close()) { 22 | /// /* ... */ 23 | /// } 24 | /// 25 | /// 26 | /// bool flag = false; 27 | /// using (new ResourceGuard(x => flag = x)) { 28 | /// /* ... */ 29 | /// } 30 | /// 31 | /// 32 | /// var stopwatch = Stopwatch.StartNew(); 33 | /// /* pausing(!) stopwatch */ 34 | /// using (new ResourceGuard(x => { 35 | /// if (x) stopwatch.Stop(); else stopwatch.Start(); 36 | /// })) { 37 | /// /* ... */ 38 | /// } 39 | /// 40 | /// 41 | /// class Indent : IResource { /*...*/ } 42 | /// Indent ind = new Indent (); 43 | /// using (new ResourceGuard(ind)) { 44 | /// /* ... */ 45 | /// } 46 | /// 47 | /// 48 | public class ResourceGuard : IDisposable { 49 | readonly Action _onDispose; 50 | readonly Action _onNewAndDispose; 51 | readonly IResource _resource; 52 | 53 | public ResourceGuard (IResource resource) { 54 | _resource = resource; 55 | _resource.Acquire (); 56 | } 57 | 58 | public ResourceGuard (Action onDispose) { 59 | _onDispose = onDispose; 60 | } 61 | 62 | public ResourceGuard (Action onNewAndDispose) { 63 | _onNewAndDispose = onNewAndDispose; 64 | _onNewAndDispose?.Invoke (true); 65 | } 66 | 67 | public void Dispose () { 68 | _onDispose?.Invoke (); 69 | _onNewAndDispose?.Invoke (false); 70 | _resource?.Release (); 71 | } 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/AuxLib.core/ResourceManagerEx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Resources; 3 | 4 | namespace core.audiamus.aux.ex { 5 | public static class ResourceManagerEx { 6 | 7 | public static ResourceManager GetDefaultResourceManager (this object o) { 8 | return o.GetType().GetDefaultResourceManager (); 9 | } 10 | 11 | public static ResourceManager GetDefaultResourceManager (this Type type) { 12 | string tableName = type.Namespace + ".Properties.Resources"; 13 | var assembly = type.Assembly; 14 | var rm = new ResourceManager (tableName, assembly); 15 | return rm; 16 | } 17 | 18 | public static ResourceManager GetTypeResourceManager (this object o) { 19 | return o.GetType().GetTypeResourceManager(); 20 | } 21 | 22 | public static ResourceManager GetTypeResourceManager (this Type type) { 23 | string tableName = type.FullName; 24 | var assembly = type.Assembly; 25 | var rm = new ResourceManager (tableName, assembly); 26 | return rm; 27 | } 28 | 29 | public static string GetStringEx (this ResourceManager rm, string val) { 30 | if (rm is null) 31 | return val; 32 | string s = null; 33 | try { 34 | s = rm.GetString (val.ToLowerInvariant()); 35 | } catch (MissingManifestResourceException) { 36 | } 37 | return s ?? val; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/AuxLib.core/ShellExecute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace core.audiamus.aux { 5 | public static class ShellExecute { 6 | public static void Url (Uri uri) => File (uri.OriginalString); 7 | 8 | public static void File (string url) { 9 | Process.Start (new ProcessStartInfo () { 10 | UseShellExecute = true, 11 | CreateNoWindow = true, 12 | FileName = url, 13 | }); 14 | 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/AuxLib.core/Singleton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace core.audiamus.aux { 4 | /// 5 | /// Implementation of the "Singleton" pattern. 6 | /// 7 | /// Type of class to be instantiated as a singleton. 8 | public class Singleton where T : class, new() { 9 | private static T __t; 10 | private static readonly object __lockable; 11 | 12 | /// 13 | /// Static ctor. Initializes the class, but does not yet create the instance. 14 | /// 15 | static Singleton () { 16 | __lockable = new object (); 17 | } 18 | 19 | /// 20 | /// Get the instance of the singleton. 21 | /// C#-style implementation as a property. 22 | /// 23 | /// 24 | /// Instance of singleton. 25 | /// 26 | public static T Instance { 27 | get { 28 | lock (__lockable) { 29 | if (__t is null) 30 | __t = new T (); 31 | 32 | return __t; 33 | } 34 | } 35 | } 36 | 37 | public static void Dispose () { 38 | lock (__lockable) { 39 | if (__t is IDisposable obj) 40 | obj.Dispose (); 41 | __t = null; 42 | } 43 | } 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/AuxLib.core/Temp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace core.audiamus.aux { 5 | public static class Temp { 6 | public static string GetPseudoUniqueString () { 7 | long ticks = DateTime.UtcNow.Ticks; 8 | int thrdid = Thread.CurrentThread.ManagedThreadId; 9 | return $"{thrdid}_{ticks}"; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/AuxLib.core/TimeUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace core.audiamus.aux { 4 | public static class TimeUtil { 5 | private readonly static DateTime EPOCH = new(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); 6 | 7 | private static double dateTimeToDouble (DateTime dt) { 8 | if (dt == default) 9 | return 0; 10 | 11 | TimeSpan ts = dt.Subtract (EPOCH); 12 | return ts.TotalSeconds; 13 | } 14 | 15 | public static int DateTimeToUnix32 (DateTime dt) => (int)dateTimeToDouble (dt); 16 | 17 | public static long DateTimeToUnix64 (DateTime dt) => (long)dateTimeToDouble (dt); 18 | 19 | public static long DateTimeToUnix64Msec (DateTime dt) { 20 | if (dt == default) 21 | return 0; 22 | 23 | TimeSpan ts = dt.Subtract (EPOCH); 24 | return (long)ts.TotalMilliseconds; 25 | } 26 | 27 | public static DateTime UnixToDateTime (long timestamp) { 28 | if (timestamp == 0) 29 | return default; 30 | 31 | DateTime dt = EPOCH.AddSeconds (timestamp); 32 | return dt; 33 | } 34 | 35 | public static DateTime UnixMsecToDateTime (long timestampMsec) { 36 | if (timestampMsec == 0) 37 | return default; 38 | 39 | DateTime dt = EPOCH.AddMilliseconds (timestampMsec); 40 | return dt; 41 | } 42 | 43 | public static int ToUnix32 (this DateTime dt) => DateTimeToUnix32 (dt); 44 | 45 | public static long ToUnix64 (this DateTime dt) => DateTimeToUnix64 (dt); 46 | 47 | public static long ToUnix64Msec (this DateTime dt) => DateTimeToUnix64Msec (dt); 48 | 49 | /// Replace time kind without changing value. 50 | /// The DateTime value to be reinterpreted. 51 | /// The new DateTime kind. 52 | /// Reinterpreted DateTime value. 53 | public static DateTime As (this DateTime dt, DateTimeKind kind) => new(dt.Ticks, kind); 54 | 55 | public static DateTime ToDateTimeFromUnix (this int timval) => UnixToDateTime (timval); 56 | 57 | public static DateTime ToDateTimeFromUnix (this long timval) => UnixToDateTime (timval); 58 | 59 | public static DateTime ToDateTimeFromUnixMsec (this long timvalMsec) => UnixMsecToDateTime (timvalMsec); 60 | 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/AuxWin.DialogBox.core/AuxWin.DialogBox.core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0-windows 5 | true 6 | core.audiamus.aux.win 7 | audiamus.aux.win.dialogbox.core 8 | audiamus 9 | 2.1.0.0 10 | 2.1.0.0 11 | Copyright © 2019 - $([System.DateTime]::UtcNow.Year) audiamus ($([System.DateTime]::UtcNow.ToString("s"))) 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/AuxWin.DialogBox.core/Win32API.cs: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // COPYRIGHT: Prosoft-Lanz 3 | //============================================================================= 4 | // 5 | // $Workfile: Win32API.cs $ 6 | // 7 | // PROJECT : CodeProject Components 8 | // VERSION : 1.00 9 | // CREATION : 19.02.2003 10 | // AUTHOR : JCL 11 | // 12 | // DETAILS : This class implement Win32 API calls 13 | // and the contants used for these calls. 14 | // 15 | //----------------------------------------------------------------------------- 16 | using System; 17 | using System.Text; 18 | using System.Drawing; 19 | using System.Windows.Forms; 20 | using System.Runtime.InteropServices; 21 | 22 | namespace core.audiamus.aux.win.Win32API 23 | { 24 | /////////////////////////////////////////////////////////////////////// 25 | #region Generic declarations 26 | 27 | /// 28 | /// Rectangle parameters exposed as a structure. 29 | /// 30 | public struct RECT 31 | { 32 | /// 33 | /// Rectangle members. 34 | /// 35 | public int left, top, right, bottom; 36 | } 37 | 38 | #endregion 39 | 40 | /////////////////////////////////////////////////////////////////////// 41 | #region Util class 42 | 43 | /// 44 | /// Utility functions. 45 | /// 46 | public sealed class API 47 | { 48 | private API() {} // To remove the constructor from the documentation! 49 | 50 | /// 51 | /// Get true multiscreen size. 52 | /// 53 | public static Rectangle TrueScreenRect 54 | { 55 | get 56 | { 57 | // get the biggest screen area 58 | Rectangle rectScreen = Screen.PrimaryScreen.WorkingArea; 59 | int left = rectScreen.Left; 60 | int top = rectScreen.Top; 61 | int right = rectScreen.Right; 62 | int bottom = rectScreen.Bottom; 63 | foreach (Screen screen in Screen.AllScreens) 64 | { 65 | left = Math.Min(left, screen.WorkingArea.Left); 66 | right = Math.Max(right, screen.WorkingArea.Right); 67 | top = Math.Min(top, screen.WorkingArea.Top); 68 | bottom = Math.Max(bottom, screen.WorkingArea.Bottom); 69 | } 70 | return new Rectangle(left, top, right-left, bottom-top); 71 | } 72 | } 73 | } 74 | 75 | #endregion 76 | 77 | /////////////////////////////////////////////////////////////////////// 78 | #region USER32 class 79 | 80 | /// 81 | /// Class to expose USER32 API functions. 82 | /// 83 | public static class USER32 84 | { 85 | [DllImport ("user32", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 86 | internal static extern int GetWindowRect(IntPtr hWnd, ref RECT rect); 87 | 88 | [DllImport("user32", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 89 | internal static extern int MoveWindow(IntPtr hWnd, int x, int y, int w, int h, int repaint); 90 | 91 | [DllImport("user32", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 92 | internal static extern IntPtr GetActiveWindow(); 93 | 94 | [DllImport("user32", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 95 | internal static extern int GetClassName(IntPtr hwnd, StringBuilder lpClassName, int nMaxCount); 96 | } 97 | #endregion 98 | 99 | #region USER32 class 100 | 101 | /// 102 | /// Class to expose KERNEL32 API functions. 103 | /// 104 | public static class KERNEL32 { 105 | [DllImport ("kernel32.dll")] 106 | internal static extern int GetCurrentThreadId (); 107 | } 108 | #endregion 109 | } 110 | -------------------------------------------------------------------------------- /src/AuxWin.lib.core/AuxWin.lib.core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0-windows 5 | true 6 | core.audiamus.aux.win 7 | audiamus.aux.win.core 8 | audiamus 9 | 2.2.0.0 10 | 2.2.0.0 11 | Copyright © 2019 - $([System.DateTime]::UtcNow.Year) audiamus ($([System.DateTime]::UtcNow.ToString("s"))) 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | True 23 | True 24 | Resources.resx 25 | 26 | 27 | 28 | 29 | 30 | ResXFileCodeGenerator 31 | Resources.Designer.cs 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/AuxWin.lib.core/ExtensionsControl.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | 5 | namespace core.audiamus.aux.win.ex { 6 | public static class ControlExtensions { 7 | public static Form GetParentForm (this Control control) { 8 | Control parent = control; 9 | while (!(parent is null || parent is Form)) 10 | parent = parent.Parent; 11 | 12 | return parent as Form; 13 | } 14 | 15 | private static readonly Dictionary __tooltips = new Dictionary (); 16 | 17 | private const char ELLIPSIS = '…'; 18 | 19 | public static void SetTextAsPathWithEllipsis (this Control label, string text = null) { 20 | if (string.IsNullOrWhiteSpace (text)) 21 | text = label.Tag as string; 22 | else 23 | label.Tag = text; 24 | 25 | label.Text = text; 26 | 27 | Size size = new (label.Width - 8, label.Height); 28 | Size reqSize = TextRenderer.MeasureText (text, label.Font); 29 | if (reqSize.Width > size.Width) { 30 | 31 | var form = label.GetParentForm (); 32 | bool succ = __tooltips.TryGetValue (form, out var tooltip); 33 | if (!succ) { 34 | tooltip = new ToolTip (); 35 | __tooltips[form] = tooltip; 36 | label.Resize += label_Resize; // once only 37 | } 38 | 39 | tooltip.SetToolTip (label, text); 40 | 41 | int pos = text.LastIndexOfAny (new char[] { '/', '\\' }); 42 | string newText; 43 | if (pos >= 0) { 44 | string left = text.Substring (0, pos); 45 | string right = text.Substring (pos); 46 | 47 | newText = shrink (left, right); 48 | if (newText is null) { 49 | pos = right.Length / 2; 50 | left = $"{ELLIPSIS}{right.Substring (0, pos)}"; 51 | right = right.Substring (pos); 52 | 53 | newText = shrink (left, right, true); 54 | } 55 | } else { 56 | pos = text.Length / 2; 57 | string left = text.Substring (0, pos); 58 | string right = text.Substring (pos); 59 | 60 | newText = shrink (left, right, true); 61 | } 62 | 63 | if (label is Label lbl) { 64 | lbl.AutoEllipsis = newText is null; 65 | } 66 | 67 | if (!(newText is null)) 68 | label.Text = newText; 69 | 70 | // local function 71 | string shrink (string left, string right, bool both = false) { 72 | bool fit = false; 73 | string newText = null; 74 | int i = 0; 75 | while (left.Length >= 4 && right.Length >= 4 && !fit) { 76 | if (!both || i % 2 == 0) 77 | left = left.Substring (0, left.Length - 1); 78 | else 79 | right = right.Substring (1); 80 | i++; 81 | newText = $"{left}{ELLIPSIS}{right}"; 82 | Size siz = TextRenderer.MeasureText (newText, label.Font); 83 | fit = siz.Width <= size.Width; 84 | } 85 | if (fit) 86 | return newText; 87 | else 88 | return null; 89 | } 90 | } 91 | } 92 | 93 | private static void label_Resize (object sender, System.EventArgs e) => 94 | (sender as Control)?.SetTextAsPathWithEllipsis (); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/AuxWin.lib.core/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | namespace core.audiamus.aux.win { 5 | public interface ISortingEvents { 6 | event EventHandler BeginSorting; 7 | event EventHandler EndSorting; 8 | } 9 | 10 | public interface ISortableBindingList : IBindingList, ISortingEvents { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/AuxWin.lib.core/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace core.audiamus.aux.win.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("core.audiamus.aux.win.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to of. 65 | /// 66 | internal static string Of { 67 | get { 68 | return ResourceManager.GetString("Of", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to Step. 74 | /// 75 | internal static string Step { 76 | get { 77 | return ResourceManager.GetString("Step", resourceCulture); 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/AuxWin.lib.core/SimpleWizard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows.Forms; 4 | using System.Linq; 5 | using R = core.audiamus.aux.win.Properties.Resources; 6 | 7 | namespace core.audiamus.aux.win { 8 | public interface ICompleted { 9 | event EventHandler Completed; 10 | } 11 | 12 | public partial class SimpleWizard : Form { 13 | record Page (Control Control, bool HasCompletion); 14 | 15 | private readonly List _wizardPages = new List (); 16 | private readonly string _textNext; 17 | private int _index = 0; 18 | 19 | public IEnumerable Pages => _wizardPages.Select (p => p.Control).ToList (); 20 | 21 | public SimpleWizard () { 22 | InitializeComponent (); 23 | _textNext = btnNext.Text; 24 | } 25 | 26 | public void AddPage (Control control) { 27 | bool hasCompletion = false; 28 | if (control is ICompleted compl) { 29 | hasCompletion = true; 30 | compl.Completed += compl_Completed; 31 | } 32 | _wizardPages.Add (new(control,hasCompletion)); 33 | } 34 | 35 | private void compl_Completed (object sender, EventArgs e) { 36 | btnNext.Enabled = true; 37 | } 38 | 39 | protected override void OnLoad (EventArgs e) { 40 | base.OnLoad (e); 41 | setPage (); 42 | } 43 | 44 | private void btnPrev_Click (object sender, EventArgs e) { 45 | _index--; 46 | setPage (); 47 | } 48 | 49 | private void btnNext_Click (object sender, EventArgs e) { 50 | _index++; 51 | setPage (); 52 | if (_index >= _wizardPages.Count) { 53 | DialogResult = DialogResult.OK; 54 | Close (); 55 | } 56 | } 57 | 58 | private void setPage () { 59 | btnPrev.Enabled = _index > 0; 60 | btnNext.Text = _index < _wizardPages.Count - 1 ? _textNext : "OK"; 61 | 62 | int step = _wizardPages.Count == 0 ? 0 : _index + 1; 63 | lblStep.Text = $"{R.Step} {step} {R.Of} {_wizardPages.Count}"; 64 | 65 | 66 | if (pnlMain.Controls.Count > 0) { 67 | var ctrl = pnlMain.Controls[0]; 68 | ctrl.Dock = DockStyle.None; 69 | pnlMain.Controls.Clear (); 70 | } 71 | if (_index < _wizardPages.Count) { 72 | var p = _wizardPages[_index]; 73 | var ctrl = p.Control; 74 | pnlMain.Controls.Add (ctrl); 75 | if (ctrl.Tag is string s) 76 | lblStep.Text += $": {s}"; 77 | pnlMain.Controls[0].Dock = DockStyle.Fill; 78 | if (p.HasCompletion) 79 | btnNext.Enabled = false; 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/AuxWin.lib.core/SimpleWizard.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/AuxWin.lib.core/SortableBindingListSuspensible.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using core.audiamus.aux.ex; 4 | 5 | namespace core.audiamus.aux.win { 6 | /// 7 | /// A ResortableBindingList that can be paused. 8 | /// 9 | /// 10 | public class SortableBindingListSuspensible : SortableBindingList { 11 | #region private fields 12 | 13 | private bool _suspended = false; 14 | private bool _dirty = false; 15 | List _backorderListAdd = new List (); 16 | List _backorderListRem = new List (); 17 | 18 | #endregion 19 | #region properties 20 | 21 | public bool Suspended { 22 | get => _suspended; 23 | set { 24 | if (_suspended == value) 25 | return; 26 | if (!value) { 27 | _dirty |= _backorderListAdd.Any () || _backorderListRem.Any (); 28 | foreach (T item in _backorderListAdd) 29 | base.Add (item); 30 | foreach (T item in _backorderListRem) 31 | base.Remove (item); 32 | _backorderListAdd.Clear (); 33 | _backorderListRem.Clear (); 34 | } 35 | 36 | _suspended = value; 37 | if (!value && _dirty) { 38 | _dirty = false; 39 | ResetBindings (); 40 | resort (); 41 | } 42 | } 43 | } 44 | 45 | public IEnumerable AllItems { 46 | get { 47 | if (Suspended) { 48 | List items = new List (); 49 | items.AddRange (this); 50 | items.AddRange (_backorderListAdd); 51 | return items.ToList(); 52 | } else 53 | return this; 54 | } 55 | } 56 | #endregion 57 | #region ctors 58 | public SortableBindingListSuspensible () : base (new List ()) { 59 | } 60 | 61 | public SortableBindingListSuspensible (IEnumerable enumeration) : base (new List (enumeration)) { 62 | } 63 | #endregion ctors 64 | #region replacing methods (non-virtual) 65 | 66 | public new void Clear () { 67 | if (Suspended) { 68 | _backorderListAdd.Clear (); 69 | _backorderListRem.Clear (); 70 | return; 71 | } 72 | base.Clear (); 73 | } 74 | 75 | public new void Add (T item) { 76 | if (Suspended) { 77 | _backorderListAdd.Add (item); 78 | return; 79 | } 80 | base.Add (item); 81 | } 82 | 83 | public new void Remove (T item) { 84 | if (Suspended) { 85 | bool succ = _backorderListAdd.Remove (item); 86 | if (!succ) 87 | _backorderListRem.Add (item); 88 | return; 89 | } 90 | base.Remove (item); 91 | } 92 | 93 | public void AddRange (IEnumerable range) { 94 | if (range is null) 95 | return; 96 | bool wasPaused = Suspended; 97 | using (new ResourceGuard (f => Suspended = f || wasPaused)) 98 | range.ForEach (o => Add (o)); 99 | } 100 | 101 | public void RemoveRange (IEnumerable range) { 102 | if (range is null) 103 | return; 104 | bool wasPaused = Suspended; 105 | using (new ResourceGuard (f => Suspended = f || wasPaused)) 106 | range.ForEach (o => Remove (o)); 107 | } 108 | 109 | 110 | #endregion 111 | #region overrides 112 | 113 | protected override void OnListChanged (System.ComponentModel.ListChangedEventArgs e) { 114 | if (Suspended) { 115 | _dirty = true; 116 | return; 117 | } 118 | base.OnListChanged (e); 119 | } 120 | #endregion 121 | 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/AuxWin32Lib.core/AuxWin32Lib.core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | core.audiamus.aux.w32 6 | audiamus.aux.w32.core 7 | audiamus 8 | 2.2.0.0 9 | 2.2.0.0 10 | Copyright © 2019 - $([System.DateTime]::UtcNow.Year) audiamus ($([System.DateTime]::UtcNow.ToString("s"))) 11 | 12 | 13 | 14 | true 15 | 16 | 17 | 18 | true 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/BooksDatabase.core/AudioQuality.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using core.audiamus.aux.ex; 4 | using core.audiamus.common; 5 | 6 | namespace core.audiamus.booksdb { 7 | public record AudioQuality (int? SampleRate, int? BitRate) : IAudioQuality; 8 | 9 | namespace ex { 10 | public static class ExCodec { 11 | 12 | public static AudioQuality ToQuality (this Codec codec) => codec.Name.ToQuality (); 13 | 14 | public static AudioQuality ToQuality(this ECodec codec) { 15 | string name = codec.ToString (); 16 | if (!name.StartsWith ("aax")) 17 | return default; 18 | 19 | var parts = name.SplitTrim ('_'); 20 | if (parts.Length < 3) 21 | return default; 22 | 23 | var qual = new AudioQuality (int.Parse (parts[1]), int.Parse (parts[2])); 24 | qual = qual with { 25 | SampleRate = qual.SampleRate * 22050 / 22 26 | }; 27 | 28 | return qual; 29 | } 30 | 31 | public static AudioQuality MaxQuality (this IEnumerable codecs) { 32 | var aaxCodecs = codecs 33 | .Select (c => c.ToQuality()) 34 | .Where (c => c is not null) 35 | .ToList (); 36 | if (!aaxCodecs.Any ()) 37 | return default; 38 | 39 | var max = aaxCodecs.Aggregate ((a, s) => { 40 | if (a is null) 41 | return s; 42 | 43 | if (s.SampleRate >= a.SampleRate && s.BitRate >= a.BitRate) 44 | return s; 45 | else 46 | return a; 47 | }); 48 | 49 | return max; 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/BooksDatabase.core/BooksDatabase.core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | core.audiamus.booksdb 6 | audiamus.booksdb.core 7 | audiamus 8 | Copyright © 2021 - $([System.DateTime]::UtcNow.Year) audiamus ($([System.DateTime]::UtcNow.ToString("s"))) 9 | 0.6.0.0 10 | 0.6.0.0 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | all 22 | runtime; build; native; contentfiles; analyzers; buildtransitive 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/BooksDatabase.core/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | namespace core.audiamus.booksdb.ex { 4 | public static class EntityExtensions { 5 | public static EConversionState ApplicableState (this Book book, bool multipart) { 6 | if (multipart && book.Components.Count > 0) { 7 | var state = book.Components 8 | .Select (c => c.Conversion.ApplicableState()) 9 | .Distinct () 10 | .Min (); 11 | return state; 12 | } else 13 | return ApplicableState(book.Conversion); 14 | 15 | 16 | } 17 | 18 | public static EConversionState ApplicableState (this Conversion conv) { 19 | if (conv.State == EConversionState.download && conv.PersistState.HasValue) 20 | return conv.PersistState.Value; 21 | else 22 | return conv.State; 23 | } 24 | 25 | public static EDownloadQuality ApplicableDownloadQuality (this Book book, bool multipart) { 26 | if (multipart && book.Components.Count > 0) { 27 | var dnldqual = book.Components 28 | .Select (c => c.ApplicableDownloadQuality()) 29 | .Distinct () 30 | .Min (); 31 | return dnldqual; 32 | } else 33 | return book.ApplicableDownloadQuality(); 34 | } 35 | 36 | public static EDownloadQuality ApplicableDownloadQuality (this IBookCommon book) => 37 | book.DownloadQuality ?? EDownloadQuality.Extreme; 38 | 39 | public static Book GetBook (this IBookCommon common) { 40 | return common switch { 41 | Book book => book, 42 | Component comp => comp.Book, 43 | Conversion conv => conv.ParentBook, 44 | _ => null, 45 | }; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/BooksDatabase.core/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using core.audiamus.common; 3 | 4 | namespace core.audiamus.booksdb { 5 | public interface IPerson { 6 | string Asin { get; set; } 7 | string Name { get; set; } 8 | ICollection Books { get; } 9 | } 10 | 11 | public interface IBookCommon : IBookMeta { 12 | new long? FileSizeBytes { get; set; } 13 | new int? RunTimeLengthSeconds { get; set; } 14 | new int? SampleRate { get; set; } 15 | new int? BitRate { get; set; } 16 | 17 | EDownloadQuality? DownloadQuality { get; set; } 18 | 19 | string LicenseKey { get; set; } 20 | string LicenseIv { get; set; } 21 | public ECodec? FileCodec { get; set; } 22 | ChapterInfo ChapterInfo { get; set; } 23 | 24 | Conversion Conversion { get; } 25 | } 26 | 27 | public interface IConversion { 28 | int Id { get; } 29 | EConversionState State { get; } 30 | string DownloadFileName { get; } 31 | string DestDirectory { get; } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/BooksDatabase.core/InternalsVisible.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo ("DynamicProxyGenAssembly2")] -------------------------------------------------------------------------------- /src/BooksDatabase.core/Migrations/20220119172449_SeriesSeq.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace core.audiamus.booksdb.Migrations 4 | { 5 | public partial class SeriesSeq : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "Sequence", 11 | table: "SeriesBooks", 12 | type: "TEXT", 13 | nullable: true); 14 | 15 | migrationBuilder.AddColumn( 16 | name: "Sort", 17 | table: "SeriesBooks", 18 | type: "INTEGER", 19 | nullable: true); 20 | } 21 | 22 | protected override void Down(MigrationBuilder migrationBuilder) 23 | { 24 | migrationBuilder.DropColumn( 25 | name: "Sequence", 26 | table: "SeriesBooks"); 27 | 28 | migrationBuilder.DropColumn( 29 | name: "Sort", 30 | table: "SeriesBooks"); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/BooksDatabase.core/Migrations/20220210175323_NullableDeleted.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace core.audiamus.booksdb.Migrations 4 | { 5 | public partial class NullableDeleted : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.DropColumn( 10 | name: "Removed", 11 | table: "Books"); 12 | 13 | migrationBuilder.AddColumn( 14 | name: "Deleted", 15 | table: "Books", 16 | type: "INTEGER", 17 | nullable: true); 18 | } 19 | 20 | protected override void Down(MigrationBuilder migrationBuilder) 21 | { 22 | migrationBuilder.DropColumn( 23 | name: "Deleted", 24 | table: "Books"); 25 | 26 | migrationBuilder.AddColumn( 27 | name: "Removed", 28 | table: "Books", 29 | type: "INTEGER", 30 | nullable: false, 31 | defaultValue: false); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/BooksDatabase.core/Migrations/20220219161122_DownloadQuality.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace core.audiamus.booksdb.Migrations 4 | { 5 | public partial class DownloadQuality : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "DownloadQuality", 11 | table: "Components", 12 | type: "INTEGER", 13 | nullable: true); 14 | 15 | migrationBuilder.AddColumn( 16 | name: "DownloadQuality", 17 | table: "Books", 18 | type: "INTEGER", 19 | nullable: true); 20 | } 21 | 22 | protected override void Down(MigrationBuilder migrationBuilder) 23 | { 24 | migrationBuilder.DropColumn( 25 | name: "DownloadQuality", 26 | table: "Components"); 27 | 28 | migrationBuilder.DropColumn( 29 | name: "DownloadQuality", 30 | table: "Books"); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/BooksDatabase.core/enums.cs: -------------------------------------------------------------------------------- 1 | namespace core.audiamus.booksdb { 2 | public enum ECodec { 3 | format4, 4 | mp4_22_32, 5 | mp4_22_64, 6 | mp4_44_64, 7 | mp4_44_128, 8 | aax, 9 | aax_22_32, 10 | aax_22_64, 11 | aax_44_64, 12 | aax_44_128, 13 | } 14 | 15 | public enum EDeliveryType { 16 | SinglePartBook, 17 | MultiPartBook, 18 | AudioPart, 19 | BookSeries, 20 | Periodical 21 | } 22 | 23 | public enum EConversionState { 24 | unknown, // strikethru globe 25 | remote, // globe 26 | download, // globe with down arrow 27 | license_granted, // key 28 | license_denied, // strikethru key 29 | downloading, // down arrow 30 | download_error, // strikethru down arrow 31 | local_locked, // lock closed 32 | unlocking, // key over lock 33 | unlocking_failed, // strikethru key over lock 34 | local_unlocked, // lock open 35 | exported, // checkmark mauve 36 | converting, // right arrow 37 | converted, // checkmark green 38 | converted_unknown,// checkmark gray 39 | conversion_error // strikethru right arrow 40 | } 41 | 42 | public enum ELicenseStatusCode { 43 | Unknown, 44 | Granted 45 | } 46 | 47 | internal enum EPseudoAsinId { 48 | none, 49 | author, 50 | narrator 51 | } 52 | 53 | public enum EDownloadQuality { 54 | Low, 55 | Normal, 56 | High, 57 | Extreme 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/CommonTypes.lib.core/CommonTypes.lib.core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | core.audiamus.common 6 | audiamus.common.types.core 7 | audiamus 8 | Copyright © 2021 - $([System.DateTime]::UtcNow.Year) audiamus ($([System.DateTime]::UtcNow.ToString("s"))) 9 | 0.3.0.0 10 | 0.3.0.0 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/CommonTypes.lib.core/Enums.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace core.audiamus.common { 8 | public enum ERegion { 9 | de, 10 | us, 11 | uk, 12 | fr, 13 | ca, 14 | it, 15 | au, 16 | @in, 17 | jp, 18 | es, 19 | br 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/CommonTypes.lib.core/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace core.audiamus.common { 8 | public interface IBookMeta : IAudioQuality { 9 | string Asin { get; } 10 | string Title { get; } 11 | string Author { get; } 12 | string MultiAuthors { get; } 13 | long? FileSizeBytes { get; } 14 | int? RunTimeLengthSeconds { get; } 15 | string Narrator { get; } 16 | string MultiNarrators { get; } 17 | string Sku { get; } 18 | string SkuLite { get; } 19 | DateTime? ReleaseDate { get; } 20 | DateTime? PurchaseDate { get; } 21 | } 22 | 23 | public interface IAudioQuality { 24 | int? SampleRate { get; } 25 | int? BitRate { get; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/CommonUtil.lib.core/CommonUtil.lib.core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | core.audiamus.util 6 | audiamus.common.util.core 7 | audiamus 8 | Copyright © 2021 - $([System.DateTime]::UtcNow.Year) audiamus ($([System.DateTime]::UtcNow.ToString("s"))) 9 | 0.3.0.0 10 | 0.3.0.0 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/CommonUtil.lib.core/FileEx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using core.audiamus.aux.w32; 3 | 4 | namespace core.audiamus.util { 5 | public interface IFileCopyCallout { 6 | void ProcessBuffer (byte[] buffer, int size, long globalOffset); 7 | } 8 | 9 | public static class FileEx { 10 | 11 | private const int BUFSIZ = 10 * 1000 * 1000; // 10 MB 12 | private const int IVL_MS = 50; 13 | 14 | 15 | public static bool Copy (string sourceFileName, string destFileName, bool overwrite, 16 | Action report = null, Func cancel = null) => 17 | Copy (sourceFileName, destFileName, overwrite, null, report, cancel); 18 | 19 | public static bool Copy (string sourceFileName, string destFileName, bool overwrite, IFileCopyCallout callout, 20 | Action report = null, Func cancel = null 21 | ) { 22 | byte[] buf = new byte[BUFSIZ]; 23 | 24 | DateTime dt0 = DateTime.Now; 25 | long ivlcnt = 0; 26 | 27 | long total = new System.IO.FileInfo (sourceFileName).Length; 28 | long count = 0; 29 | 30 | using (var threadProgress = new ThreadProgressPerMille (report)) { 31 | using (WinFileIO wfioRd = new WinFileIO (buf), wfioWr = new WinFileIO (buf)) { 32 | wfioRd.OpenForReading (sourceFileName); 33 | wfioWr.OpenForWriting (destFileName, overwrite); 34 | 35 | int read = 0; 36 | while (true) { 37 | 38 | if (cancel?.Invoke () ?? false) 39 | return false; 40 | 41 | read = wfioRd.ReadBlocks (BUFSIZ); 42 | if (read <= 0) 43 | break; 44 | 45 | callout?.ProcessBuffer (buf, read, count); 46 | 47 | wfioWr.Write (read); 48 | 49 | count += read; 50 | DateTime dt = DateTime.Now; 51 | long tot_ms = (int)(dt - dt0).TotalMilliseconds; 52 | long q = tot_ms / IVL_MS; 53 | if (q <= ivlcnt) 54 | continue; 55 | 56 | ivlcnt = q; 57 | threadProgress.Report ((double)count / total); 58 | }; 59 | } 60 | } 61 | return true; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/CommonUtil.lib.core/Records.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace core.audiamus.util { 4 | 5 | public record ProgressMessage ( 6 | int? ItemCount, 7 | int? IncItem, 8 | int? IncStepsPerCent, 9 | int? IncStepsPerMille 10 | ); 11 | 12 | public interface IPackageInfo { 13 | string AppName { get; } 14 | Version Version { get; } 15 | bool Preview { get; } 16 | bool DefaultApp { get; } 17 | string Desc { get; } 18 | } 19 | 20 | public record UpdateInteractionMessage (EUpdateInteract Kind, IPackageInfo PckInfo); 21 | 22 | public record PackageInfo { 23 | public string Url { get; init; } 24 | public string AppName { get; init; } 25 | public string Version { get; init; } 26 | public bool Preview { get; init; } 27 | public string Desc { get; init; } 28 | public string Md5 { get; init; } 29 | } 30 | 31 | public record PackageInfoLocal : PackageInfo, IPackageInfo { 32 | public new Version Version { get; init; } 33 | public string SetupFile { get; init; } 34 | public bool DefaultApp { get; init; } 35 | 36 | public PackageInfoLocal () { } 37 | public PackageInfoLocal (PackageInfo pi) { 38 | Url = pi.Url; 39 | AppName = pi.AppName; 40 | Version = tryParse (pi.Version); 41 | Preview = pi.Preview; 42 | Desc = pi.Desc; 43 | Md5 = pi.Md5; 44 | 45 | static Version tryParse (string s) { 46 | bool succ = Version.TryParse (s, out Version version); 47 | return succ ? version : null; 48 | } 49 | } 50 | } 51 | 52 | 53 | } 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/CommonUtil.lib.core/Settings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace core.audiamus.util { 8 | public interface IUpdateSettings { 9 | EOnlineUpdate OnlineUpdate { get; } 10 | } 11 | 12 | public class UpdateSettings : IUpdateSettings { 13 | public EOnlineUpdate OnlineUpdate { get; set; } = EOnlineUpdate.promptForDownload; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/CommonUtil.lib.core/ThreadProgress.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace core.audiamus.util { 4 | public abstract class ThreadProgressBase : IDisposable { 5 | 6 | private readonly Action _report; 7 | 8 | private int _accuValuePerMax; 9 | 10 | protected abstract int Max { get; } 11 | 12 | protected ThreadProgressBase (Action report) { 13 | _report = report; 14 | } 15 | 16 | public void Dispose () { 17 | int inc = Max - _accuValuePerMax; 18 | if (inc > 0) 19 | _report?.Invoke (getProgressMessage(inc)); 20 | } 21 | 22 | public void Report (double value) { 23 | int val = (int)(value * Max); 24 | int total = Math.Min (Max, val); 25 | int inc = total - _accuValuePerMax; 26 | _accuValuePerMax = total; 27 | if (inc > 0) 28 | _report?.Invoke (getProgressMessage (inc)); 29 | } 30 | 31 | protected abstract T getProgressMessage (int inc); 32 | } 33 | 34 | public class ThreadProgressPerMille : ThreadProgressBase { 35 | protected override int Max => 1000; 36 | 37 | public ThreadProgressPerMille (Action report) : base (report) { } 38 | 39 | protected override ProgressMessage getProgressMessage (int inc) => new(null, null, null, inc); 40 | } 41 | 42 | public class ThreadProgressPerCent : ThreadProgressBase { 43 | protected override int Max => 100; 44 | 45 | public ThreadProgressPerCent (Action report) : base (report) { } 46 | 47 | protected override ProgressMessage getProgressMessage (int inc) => new(null, null, inc, null); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/CommonUtil.lib.core/ToStringConverters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using core.audiamus.aux.diagn; 3 | using core.audiamus.aux.ex; 4 | 5 | namespace core.audiamus.util { 6 | public class ToStringConverterActivationCode : ToStringConverter { 7 | public override string ToString (object o, string format = null) { 8 | try { 9 | uint? ac = (uint?)o; 10 | return ac.HasValue ? "XXXXXXXX" : null; 11 | } catch ( Exception ) { 12 | return null; 13 | } 14 | } 15 | } 16 | 17 | public class ToStringConverterPath : ToStringConverter { 18 | public override string ToString (object o, string format = null) { 19 | if (o is string s) 20 | return s.SubstitUser (); 21 | else 22 | return null; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/CommonUtil.lib.core/enums.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace core.audiamus.util { 8 | public enum EOnlineUpdate { 9 | no, 10 | promptForDownload, 11 | promptForInstall 12 | } 13 | 14 | public enum EUpdateInteract { 15 | newVersAvail, 16 | installNow, 17 | installLater, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/AboutForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using core.audiamus.aux; 4 | using static core.audiamus.aux.ApplEnv; 5 | 6 | namespace core.audiamus.connect.app.gui { 7 | partial class AboutForm : Form { 8 | public AboutForm () { 9 | InitializeComponent (); 10 | Text += AssemblyTitle; 11 | 12 | } 13 | 14 | protected override void OnLoad (EventArgs e) { 15 | base.OnLoad (e); 16 | lblProduct.Text = AssemblyProduct; 17 | lblVersion.Text += AssemblyVersion; 18 | lblCopyright.Text += assemblyCopyright(); 19 | 20 | static string assemblyCopyright () { 21 | int pos = AssemblyCopyright.IndexOf ('('); 22 | if (pos < 0) 23 | return AssemblyCopyright; 24 | else 25 | return AssemblyCopyright.Substring (0, pos).Trim(); 26 | 27 | } 28 | } 29 | 30 | private void linkLabelHomepage_LinkClicked (object sender, LinkLabelLinkClickedEventArgs e) { 31 | var s = ((LinkLabel)sender).Text; 32 | ShellExecute.File (s); 33 | } 34 | } 35 | 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/AppSettings.cs: -------------------------------------------------------------------------------- 1 | namespace core.audiamus.connect.app.gui { 2 | class AppSettings { 3 | public uint? LogLevel { get; set; } 4 | public bool DbgOnlineUpdate { get; set; } 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/BookLibConnect.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.app.gui.core/BookLibConnect.odt -------------------------------------------------------------------------------- /src/Connect.app.gui.core/Connect.app.gui.core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net6.0-windows 6 | true 7 | audiamus 8 | BookLibConnect 9 | Book Lib Connect 10 | core.audiamus.connect.app.gui 11 | Copyright © 2021 - $([System.DateTime]::UtcNow.Year) audiamus ($([System.DateTime]::UtcNow.ToString("s"))) 12 | 0.13.1.0 13 | 0.13.1.0 14 | Resources\audio.ico 15 | 16 | 17 | 18 | x64 19 | 20 | 21 | 22 | x64 23 | 24 | 25 | 26 | 27 | all 28 | runtime; build; native; contentfiles; analyzers; buildtransitive 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | True 44 | True 45 | Resources.resx 46 | 47 | 48 | True 49 | True 50 | Settings.settings 51 | 52 | 53 | UserControl 54 | 55 | 56 | 57 | 58 | 59 | ResXFileCodeGenerator 60 | Resources.Designer.cs 61 | 62 | 63 | 64 | 65 | 66 | PreserveNewest 67 | 68 | 69 | SettingsSingleFileGenerator 70 | Settings.Designer.cs 71 | 72 | 73 | Never 74 | 75 | 76 | PreserveNewest 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/ConversionContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using core.audiamus.connect; 4 | using core.audiamus.util; 5 | 6 | namespace core.audiamus.connect.app.gui { 7 | class ConversionContext : ICancellation { 8 | public IProgress Progress { get; } 9 | public CancellationToken CancellationToken { get; } 10 | 11 | public ConversionContext (IProgress progress, CancellationToken token) { 12 | Progress = progress; 13 | CancellationToken = token; 14 | } 15 | 16 | public void Init (int nItems) { 17 | Progress?.Report (new (nItems, null, null, null)); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Forms; 4 | using core.audiamus.aux; 5 | 6 | namespace core.audiamus.connect.app.gui { 7 | static class Program { 8 | /// 9 | /// The main entry point for the application. 10 | /// 11 | [STAThread] 12 | static void Main (string[] args) { 13 | Application.SetHighDpiMode (HighDpiMode.PerMonitorV2); 14 | Application.EnableVisualStyles (); 15 | Application.SetCompatibleTextRenderingDefault (false); 16 | 17 | CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; 18 | 19 | var appSettings = SettingsManager.GetAppSettings (); 20 | if (appSettings?.LogLevel is not null) 21 | Logging.Level = (int)appSettings.LogLevel.Value; 22 | else { 23 | ArgParser argParser = new ArgParser (args); 24 | uint? level = argParser.FindUIntArg ("Log"); 25 | if (level.HasValue) 26 | Logging.Level = (int)level.Value; 27 | else 28 | Logging.Level = 3; 29 | } 30 | Logging.InstantFlush = true; 31 | 32 | Application.Run (new MainForm ()); 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/ProgressProcessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using core.audiamus.util; 4 | 5 | namespace core.audiamus.connect.app.gui { 6 | abstract class ProgressProcessorBase { 7 | public Progress Progress { get; } 8 | 9 | protected ProgressProcessorBase () { 10 | Progress = new Progress (); 11 | Progress.ProgressChanged += report; 12 | } 13 | 14 | private void report (object sender, ProgressMessage msg) => report (msg); 15 | 16 | protected abstract void report (ProgressMessage msg); 17 | } 18 | 19 | class ProgressProcessor1 : ProgressProcessorBase { 20 | private readonly ProgressBar _progbarConvert; 21 | 22 | private int _maxItems; 23 | private int _maxConvert; 24 | private int _accuValueConvert; 25 | 26 | public ProgressProcessor1 (ProgressBar progbarConvert) { 27 | _progbarConvert = progbarConvert; 28 | } 29 | 30 | protected override void report (ProgressMessage msg) { 31 | if (msg.ItemCount.HasValue) { 32 | _maxItems = msg.ItemCount.Value; 33 | 34 | _maxConvert = msg.ItemCount.Value * 1000; 35 | _accuValueConvert = 0; 36 | _progbarConvert.Value = 0; 37 | _progbarConvert.Maximum = _maxConvert; 38 | } 39 | 40 | if (msg.IncStepsPerMille.HasValue) { 41 | _accuValueConvert += msg.IncStepsPerMille.Value; 42 | _accuValueConvert = Math.Min (_accuValueConvert, _maxConvert); 43 | _progbarConvert.Value = _accuValueConvert; 44 | } 45 | 46 | } 47 | } 48 | 49 | class ProgressProcessor2 : ProgressProcessorBase { 50 | private readonly ProgressBar _progbarDecrypt; 51 | private readonly ProgressBar _progbarDnld; 52 | 53 | private int _nItems; 54 | private int _maxDecrypt; 55 | private int _accuValueDecrypt; 56 | private int _maxDnld; 57 | private int _accuValueDnld; 58 | 59 | public ProgressProcessor2 (ProgressBar progbarItems, ProgressBar progbarDnld) { 60 | _progbarDecrypt = progbarItems; 61 | _progbarDnld = progbarDnld; 62 | } 63 | 64 | protected override void report (ProgressMessage msg) { 65 | if (msg.ItemCount.HasValue) { 66 | _nItems = msg.ItemCount.Value; 67 | _maxDecrypt = _nItems * 100; 68 | _accuValueDecrypt = 0; 69 | _progbarDecrypt.Value = 0; 70 | _progbarDecrypt.Maximum = _maxDecrypt; 71 | 72 | _maxDnld = 1000; 73 | _accuValueDnld = 0; 74 | _progbarDnld.Value = 0; 75 | _progbarDnld.Maximum = _maxDnld; 76 | } 77 | 78 | if (msg.IncItem.HasValue) { 79 | _maxDnld = 1000; 80 | _accuValueDnld = 0; 81 | _progbarDnld.Value = 0; 82 | _progbarDnld.Maximum = _maxDnld; 83 | } 84 | 85 | if (msg.IncStepsPerMille.HasValue) { 86 | _accuValueDnld += msg.IncStepsPerMille.Value; 87 | _accuValueDnld = Math.Min (_accuValueDnld, _maxDnld); 88 | _progbarDnld.Value = _accuValueDnld; 89 | } 90 | 91 | if (msg.IncStepsPerCent.HasValue) { 92 | _accuValueDecrypt += msg.IncStepsPerCent.Value; 93 | _accuValueDecrypt = Math.Min (_accuValueDecrypt, _maxDecrypt); 94 | _progbarDecrypt.Value = _accuValueDecrypt; 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\Release\net6.0-windows\publish\ 10 | FileSystem 11 | net6.0-windows 12 | win-x64 13 | false 14 | true 15 | false 16 | 17 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace core.audiamus.connect.app.gui.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.7.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Connect.app.gui.core": { 4 | "commandName": "Project", 5 | "commandLineArgs": "-Log=4" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /src/Connect.app.gui.core/Resources/audio.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.app.gui.core/Resources/audio.ico -------------------------------------------------------------------------------- /src/Connect.app.gui.core/Resources/audio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.app.gui.core/Resources/audio.png -------------------------------------------------------------------------------- /src/Connect.app.gui.core/UserSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using core.audiamus.aux; 3 | using core.audiamus.util; 4 | 5 | namespace core.audiamus.connect.app.gui { 6 | 7 | public class UserSettings : IUserSettings, IInitSettings { 8 | public UpdateSettings UpdateSettings { get; set; } = new UpdateSettings (); 9 | public DownloadSettings DownloadSettings { get; set; } = new DownloadSettings (); 10 | public ConfigSettings ConfigSettings { get; set; } = new ConfigSettings (); 11 | public ExportSettings ExportSettings { get; set; } = new ExportSettings (); 12 | 13 | public void Init () { 14 | DownloadSettings.ChangedSettings += onChangedSettings; 15 | ConfigSettings.ChangedSettings += onChangedSettings; 16 | ExportSettings.ChangedSettings += onChangedSettings; 17 | } 18 | 19 | private void onChangedSettings (object sender, EventArgs e) => this.Save (); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/WaitForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace core.audiamus.connect.app.gui { 12 | public partial class WaitForm : Form { 13 | public WaitForm () { 14 | InitializeComponent (); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/WaitForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/WizStepDownload.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using core.audiamus.aux.win; 4 | 5 | namespace core.audiamus.connect.app.gui { 6 | public partial class WizStepDownload : UserControl, ICompleted { 7 | public event EventHandler Completed; 8 | 9 | private Func BtnAction { get; } 10 | 11 | public WizStepDownload (Func action) { 12 | InitializeComponent (); 13 | BtnAction = action; 14 | } 15 | 16 | private void button1_Click (object sender, EventArgs e) { 17 | bool succ = BtnAction (); 18 | if (succ) 19 | Completed?.Invoke (this, EventArgs.Empty); 20 | 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/WizStepDownload.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/WizStepExport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using core.audiamus.aux; 4 | using core.audiamus.aux.win; 5 | using core.audiamus.connect; 6 | 7 | namespace core.audiamus.connect.app.gui { 8 | public partial class WizStepExport : UserControl, ICompleted { 9 | public event EventHandler Completed; 10 | 11 | private Func BtnAction { get; } 12 | private ExportSettings Settings { get; } 13 | private bool _ignoreFlag; 14 | 15 | public WizStepExport (Func btnAction, ExportSettings settings) { 16 | 17 | InitializeComponent (); 18 | BtnAction = btnAction; 19 | Settings = settings; 20 | 21 | using var _ = new ResourceGuard (x => _ignoreFlag = x); 22 | button1.Enabled = false; 23 | 24 | if (Settings.ExportToAax.HasValue) { 25 | checkBox1.Checked = Settings.ExportToAax.Value; 26 | } 27 | } 28 | 29 | private void checkBox1_CheckedChanged (object sender, EventArgs e) { 30 | if (checkBox1.CheckState != CheckState.Indeterminate) 31 | Settings.ExportToAax = checkBox1.Checked; 32 | enable (); 33 | } 34 | 35 | private void button1_Click (object sender, EventArgs e) { 36 | BtnAction (); 37 | enable (); 38 | } 39 | 40 | private void enable () { 41 | if (_ignoreFlag) 42 | return; 43 | button1.Enabled = Settings.ExportToAax ?? false; 44 | bool succ = Settings.ExportToAax.HasValue && 45 | (!Settings.ExportToAax.Value || Settings.ExportDirectory is not null); 46 | if (succ) 47 | Completed?.Invoke (this, EventArgs.Empty); 48 | 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/WizStepExport.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/WizStepHelp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace core.audiamus.connect.app.gui { 5 | public partial class WizStepHelp : UserControl { 6 | 7 | private Action BtnAction { get; } 8 | 9 | public WizStepHelp (Action action) { 10 | InitializeComponent (); 11 | BtnAction = action; 12 | } 13 | 14 | private void button1_Click (object sender, EventArgs e) { 15 | BtnAction (); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/WizStepHelp.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/WizStepProfile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using core.audiamus.aux.win; 4 | using core.audiamus.connect.ui; 5 | 6 | namespace core.audiamus.connect.app.gui { 7 | public partial class WizStepProfile : UserControl, ICompleted { 8 | public event EventHandler Completed; 9 | 10 | private AudibleClient Client { get; } 11 | 12 | public WizStepProfile (AudibleClient client) { 13 | InitializeComponent (); 14 | Client = client; 15 | } 16 | 17 | private void button1_Click (object sender, EventArgs e) { 18 | var dlg = new NewProfileForm (Client, null); 19 | var result = dlg.ShowDialog (); 20 | 21 | bool succ = result == DialogResult.OK && dlg.ProfileKey is not null; 22 | if (succ) { 23 | button1.Enabled = false; 24 | Completed?.Invoke (this, EventArgs.Empty); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/WizStepProfile.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Connect.app.gui.core/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "LogLevel": null 3 | } -------------------------------------------------------------------------------- /src/Connect.lib.core/AccountAlias.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using core.audiamus.common; 4 | 5 | namespace core.audiamus.connect { 6 | 7 | public class AccountAliasContext { 8 | public int LocalId { get; } 9 | public string CustomerName { get; } 10 | public IEnumerable Hashes { get; } 11 | public string Alias { get; set; } 12 | 13 | public AccountAliasContext (int localId, string customerName, IEnumerable hashes) { 14 | LocalId = localId; 15 | CustomerName = customerName; 16 | Hashes = hashes; 17 | } 18 | } 19 | 20 | public class ProfileAliasKey : IEquatable, IProfileAliasKey { 21 | public string AccountAlias { get; set; } 22 | public ERegion Region { get; set; } 23 | 24 | public ProfileAliasKey () { } 25 | public ProfileAliasKey (IProfileAliasKey other) : this (other.Region, other.AccountAlias) { } 26 | public ProfileAliasKey (ERegion region, string accountAlias) { 27 | Region = region; 28 | AccountAlias = accountAlias; 29 | } 30 | 31 | public override string ToString () => $"{AccountAlias}; {Region}"; 32 | public bool Equals (IProfileAliasKey other) { 33 | return Region == other.Region && string.Equals (AccountAlias, other.AccountAlias); 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/Connect.lib.core/Anonymizer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using core.audiamus.aux.ex; 3 | 4 | namespace core.audiamus.connect.ex { 5 | static class Anonymizer { 6 | 7 | private static Dictionary Usernames { get; } = new Dictionary (); 8 | private static Dictionary Passwords { get; } = new Dictionary (); 9 | 10 | public static string AnonymizeCredentials (this string source, Credentials creds) { 11 | if (creds is null) 12 | return source; 13 | return source.AnonymizeUsernamePassword (creds.Username, creds.Password); 14 | } 15 | 16 | public static string AnonymizeUsernamePassword (this string source, string username, string password) { 17 | string intermed = source.AnonymizeUsername (username); 18 | string result = intermed.AnonymizePassword (password); 19 | return result; 20 | } 21 | 22 | public static string AnonymizeUsername (this string source, string username) { 23 | if (username.IsNullOrWhiteSpace ()) 24 | return source; 25 | const string STUB = "ACCNT"; 26 | return replaceWithSubstitute (Usernames, source, username, STUB); 27 | } 28 | 29 | public static string AnonymizePassword (this string source, string password) { 30 | if (password.IsNullOrWhiteSpace ()) 31 | return source; 32 | const string STUB = "PASSW"; 33 | return replaceWithSubstitute (Passwords, source, password, STUB); 34 | } 35 | 36 | public static string AnonymizeUsername (this string username) => AnonymizeUsername (null, username); 37 | public static string AnonymizePassword (this string password) => AnonymizePassword (null, password); 38 | 39 | private static string replaceWithSubstitute (Dictionary dict, string source, string password, string STUB) { 40 | if (source is null) 41 | return null; 42 | string subst = getSubstitute (dict, password, STUB); 43 | if (source is null) 44 | return subst; 45 | else 46 | return source.Replace (password, subst); 47 | } 48 | 49 | private static string getSubstitute (Dictionary dict, string key, string stub) { 50 | const char C = '¿'; 51 | string lkey = key.ToLower (); 52 | uint ukey = lkey.Checksum32 (); 53 | lock (dict) { 54 | bool succ = dict.TryGetValue (ukey, out string subst); 55 | if (!succ) { 56 | int n = dict.Count + 1; 57 | subst = $"{C}{stub}{n}{C}"; 58 | dict[ukey] = subst; 59 | } 60 | return subst; 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Connect.lib.core/Connect.lib.core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | audiamus 6 | core.audiamus.connect 7 | audiamus.connect.core 8 | audiamus 9 | Copyright © 2021 - $([System.DateTime]::UtcNow.Year) audiamus ($([System.DateTime]::UtcNow.ToString("s"))) 10 | 0.13.1.0 11 | 0.13.1.0 12 | 13 | 14 | 15 | x64 16 | 17 | 18 | 19 | x64 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | True 41 | True 42 | Resources.resx 43 | 44 | 45 | 46 | 47 | 48 | ResXFileCodeGenerator 49 | Resources.Designer.cs 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/Connect.lib.core/ConsoleExternalLoginCallback.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using core.audiamus.aux; 4 | 5 | namespace core.audiamus.connect { 6 | public static class ConsoleExternalLogin { 7 | public static Uri Callback (Uri uri) { 8 | 9 | ShellExecute.Url (uri); 10 | 11 | Console.WriteLine ("Paste final URL from browser:"); 12 | while (true) { 13 | string finalUrl = Console.ReadLine (); 14 | bool succ = Uri.TryCreate (finalUrl, UriKind.Absolute, out Uri finalUri); 15 | if (!succ) { 16 | Console.WriteLine ("Invalid URL. Try again:"); 17 | continue; 18 | } 19 | Authorization auth = Authorization.Create (finalUri); 20 | if (auth is null) { 21 | Console.WriteLine ("URL does not contain authorization. Try again:"); 22 | continue; 23 | } 24 | //TokenBearer token = TokenBearer.Create (finalUri); 25 | //if (token is null) { 26 | // Console.WriteLine ("URL does not contain token. Try again:"); 27 | // continue; 28 | //} 29 | return finalUri; 30 | 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Connect.lib.core/Delegates.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using core.audiamus.booksdb; 3 | 4 | namespace core.audiamus.connect { 5 | public delegate void ConvertDelegate (Book book, T context, Action onNewStateCallback) where T : ICancellation; 6 | 7 | delegate ConfigurationTokenResult ConfigTokenDelegate (bool enforce = false); 8 | } 9 | -------------------------------------------------------------------------------- /src/Connect.lib.core/HttpClientEx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Http; 4 | 5 | namespace core.audiamus.connect { 6 | class HttpClientEx : HttpClient { 7 | public CookieContainer CookieContainer { get; } = new CookieContainer (); 8 | 9 | private HttpClientEx (HttpMessageHandler handler) : base (handler) { } 10 | 11 | public static HttpClientEx Create (Uri baseUri) { 12 | var handler = new HttpClientHandler { 13 | AllowAutoRedirect = false, 14 | AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate 15 | }; 16 | return create (handler, baseUri); 17 | } 18 | 19 | private static HttpClientEx create (HttpClientHandler handler, Uri baseUri) { 20 | var client = new HttpClientEx (handler); 21 | client.BaseAddress = baseUri; 22 | 23 | handler.AllowAutoRedirect = false; 24 | handler.CookieContainer = client.CookieContainer; 25 | 26 | return client; 27 | } 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Connect.lib.core/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using core.audiamus.aux; 6 | using core.audiamus.booksdb; 7 | using core.audiamus.common; 8 | 9 | namespace core.audiamus.connect { 10 | interface IProfile { 11 | uint Id { get; } 12 | bool PreAmazon { get; } 13 | ERegion Region { get; } 14 | IAuthorization Authorization { get; } 15 | ICustomerInfo CustomerInfo { get; } 16 | IDeviceInfo DeviceInfo { get; } 17 | ITokenBearer Token { get; } 18 | IEnumerable> Cookies { get; } 19 | string PrivateKey { get; } 20 | string AdpToken { get; } 21 | string StoreAuthentCookie { get; } 22 | 23 | void Refresh (TokenBearer token); 24 | } 25 | 26 | interface IAuthorization { 27 | string AuthorizationCode { get;} 28 | string CodeVerifier { get; } 29 | } 30 | 31 | interface ITokenBearer { 32 | string RefreshToken { get; } 33 | string AccessToken { get; } 34 | DateTime Expiration { get; } 35 | } 36 | 37 | interface IDeviceInfo { 38 | string Type { get; } 39 | string Name { get; } 40 | string Serial { get; set; } 41 | } 42 | 43 | interface ICustomerInfo { 44 | string Name { get; } 45 | string AccountId { get; } 46 | } 47 | 48 | public interface IProfileKey { 49 | uint Id { get; } 50 | ERegion Region { get; } 51 | string AccountId { get; } 52 | } 53 | 54 | public interface IProfileKeyEx : IProfileKey { 55 | string AccountName { get; } 56 | string DeviceName{ get; } 57 | } 58 | 59 | public interface IProfileAliasKey { 60 | string AccountAlias { get; } 61 | ERegion Region { get; } 62 | } 63 | 64 | public interface ICancellation { 65 | CancellationToken CancellationToken { get; } 66 | } 67 | 68 | public interface IBookLibrary { 69 | IEnumerable GetBooks (ProfileId profileId); 70 | void GetChapters (IBookCommon item); 71 | IEnumerable GetChaptersFlattened (IBookCommon item, List> accuChapters); 72 | EConversionState GetPersistentState (Conversion conversion); 73 | void SavePersistentState (Conversion conversion, EConversionState state); 74 | } 75 | 76 | public interface IAudibleApi : IProfileAliasKey, IDisposable { 77 | Func RefreshTokenAsyncFunc { get; } 78 | Func GetAccountAliasFunc { set; } 79 | Task GetLibraryAsync (bool resync); 80 | Task GetAccountInfoAsync (); 81 | Task GetUserProfileAsync (); 82 | Task GetActivationBytesAsync (); 83 | Task GetDownloadLicenseAsync ( 84 | string asin, EDownloadQuality quality 85 | ); 86 | Task DownloadAsync ( 87 | Conversion conversion, Action progressAction, CancellationToken cancToken 88 | ); 89 | Task DecryptAsync ( 90 | Conversion conversion, Action progressAction, CancellationToken cancToken 91 | ); 92 | Task DownloadCoverImagesAsync (); 93 | Task UpdateMetaInfo (IEnumerable components, Action> onDone); 94 | Task GetDownloadLicenseAndSaveAsync (Conversion conversion, EDownloadQuality quality); 95 | IEnumerable GetBooks (); 96 | void SavePersistentState (Conversion conversion, EConversionState state); 97 | void RestorePersistentState (Conversion conversion); 98 | EConversionState GetPersistentState (Conversion conversion); 99 | void CheckUpdateFilesAndState ( 100 | IDownloadSettings downloadSettings, 101 | IExportSettings exportSettings, 102 | Action callbackRefConversion, 103 | IInteractionCallback, bool?> interactCallback 104 | ); 105 | 106 | } 107 | } -------------------------------------------------------------------------------- /src/Connect.lib.core/InternalsVisible.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo ("audiamus.connect.test.core")] 4 | [assembly: InternalsVisibleTo ("audiamus.connect.app.console.core")] 5 | -------------------------------------------------------------------------------- /src/Connect.lib.core/Localization.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using core.audiamus.common; 3 | 4 | namespace core.audiamus.connect { 5 | 6 | interface ILocale { 7 | ERegion CountryCode { get; } 8 | string Domain { get; } 9 | string MarketPlaceId { get; } 10 | } 11 | 12 | record LocaleTemplate (ERegion CountryCode, string Domain, string MarketPlaceId) : ILocale { } 13 | 14 | static class Locale { 15 | static readonly Dictionary LocaleTemplates = new () { 16 | { ERegion.de, new (ERegion.de, "de", "AN7V1F1VY261K") }, 17 | { ERegion.us, new (ERegion.us, "com", "AF2M0KC94RCEA") }, 18 | { ERegion.uk, new (ERegion.uk, "co.uk", "A2I9A3Q2GNFNGQ") }, 19 | { ERegion.fr, new (ERegion.fr, "fr", "A2728XDNODOQ8T") }, 20 | { ERegion.ca, new (ERegion.ca, "ca", "A2CQZ5RBY40XE") }, 21 | { ERegion.it, new (ERegion.it, "it", "A2N7FU2W2BU2ZC") }, 22 | { ERegion.au, new (ERegion.au, "com.au", "AN7EY7DTAW63G") }, 23 | { ERegion.@in, new (ERegion.@in, "in", "AJO3FBRUE6J4S") }, 24 | { ERegion.jp, new (ERegion.jp, "co.jp", "A1QAP3MOU4173J") }, 25 | { ERegion.es, new (ERegion.es, "es", "ALMIKO4SZCSAR") }, 26 | { ERegion.br, new (ERegion.br, "com.br", "A10J1VAYUDTYRN") }, 27 | }; 28 | 29 | public static ILocale FromCountryCode (this ERegion countryCode) { 30 | bool succ = LocaleTemplates.TryGetValue(countryCode, out var locale); 31 | if (!succ) 32 | return null; 33 | return locale; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Connect.lib.core/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace core.audiamus.connect.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("core.audiamus.connect.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to .m4b. 65 | /// 66 | internal static string DecryptedFileExt { 67 | get { 68 | return ResourceManager.GetString("DecryptedFileExt", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to .aaxc. 74 | /// 75 | internal static string EncryptedFileExt { 76 | get { 77 | return ResourceManager.GetString("EncryptedFileExt", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to .aax. 83 | /// 84 | internal static string ExportedFileExt { 85 | get { 86 | return ResourceManager.GetString("ExportedFileExt", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Connect.lib.core/Records.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | 5 | using core.audiamus.aux.ex; 6 | using core.audiamus.booksdb; 7 | using core.audiamus.common; 8 | using core.audiamus.util; 9 | 10 | namespace core.audiamus.connect { 11 | public record Callbacks { 12 | public Func CaptchaCallback { get; init; } 13 | public Action ApprovalCallback { get; init; } 14 | public Func MfaCallback { get; init; } 15 | public Func CvfCallback { get; init; } 16 | 17 | public Func ExternalLoginCallback { get; init; } 18 | public Func DeregisterDeviceConfirmCallback { get; init; } 19 | public Func GetAccountAliasFunc { get; init; } 20 | }; 21 | 22 | public record Credentials (string Username, string Password); 23 | 24 | public record CredentialsUrl (Credentials Credentials, string BaseUriString) : 25 | Credentials (Credentials.Username, Credentials.Password); 26 | 27 | public record RegisterResult ( 28 | EAuthorizeResult Result, 29 | IProfileKeyEx NewProfileKey, 30 | string PrevDeviceName 31 | ); 32 | 33 | public record ProfileKey (uint Id, ERegion Region, string AccountId) : IProfileKey { 34 | public override string ToString () => 35 | $"{GetType().Name} {nameof (Id)}={Id}, {nameof (Region)}={Region}, {nameof (AccountId)}=#<{AccountId.Checksum32 ()}>"; 36 | } 37 | public record ProfileKeyEx (uint Id, ERegion Region, string AccountName, string AccountId, string DeviceName) : 38 | ProfileKey (Id, Region, AccountId), IProfileKeyEx { 39 | public override string ToString () => 40 | $"{base.ToString()}, {nameof (AccountName)}=#<{AccountName.Checksum32}>, {nameof (DeviceName)}=#<{DeviceName.Checksum32 ()}>"; 41 | } 42 | 43 | public record ProfileId (int AccountId, ERegion Region); 44 | 45 | public record AccountAlias (string AccountId, string Alias); 46 | 47 | public record SimpleConversionContext ( 48 | IProgress Progress, 49 | CancellationToken CancellationToken 50 | ); 51 | 52 | public record BookLibInteract (EBookLibInteract Kind); 53 | 54 | public record ChapterExtract (string Title, int Length); 55 | 56 | record ProductComponentPair (adb.json.Product Product, Component Component); 57 | 58 | record ProfileBundle (IProfile Profile, IProfileKey Key, IProfileAliasKey AliasKey); 59 | 60 | record BookCompositeLists ( 61 | List BookAsins, 62 | List Conversions, 63 | List Components, 64 | List Series, 65 | List SeriesBooks, 66 | List Authors, 67 | List Narrators, 68 | List Genres, 69 | List Ladders, 70 | List Rungs, 71 | List Codecs 72 | ); 73 | 74 | record ConfigurationTokenResult (string Token, bool Weak); 75 | 76 | } 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/Connect.lib.core/ReducedChoicesDownloadQuality.cs: -------------------------------------------------------------------------------- 1 |  2 | using core.audiamus.booksdb; 3 | 4 | namespace core.audiamus.connect { 5 | public enum EDownloadQualityReducedChoices { 6 | Normal, 7 | High, 8 | } 9 | 10 | public static class DownloadQualityExtensions { 11 | public static EDownloadQuality ToFullChoices (this EDownloadQualityReducedChoices value) { 12 | return value switch { 13 | EDownloadQualityReducedChoices.High => EDownloadQuality.High, 14 | _ => EDownloadQuality.Normal 15 | }; 16 | } 17 | public static EDownloadQualityReducedChoices ToReducedChoices (this EDownloadQuality value) { 18 | return value switch { 19 | EDownloadQuality.Extreme => EDownloadQualityReducedChoices.High, 20 | EDownloadQuality.High => EDownloadQualityReducedChoices.High, 21 | _ => EDownloadQualityReducedChoices.Normal 22 | }; 23 | } 24 | 25 | public static EDownloadQuality ReduceChoices (this EDownloadQuality value) => 26 | value.ToReducedChoices ().ToFullChoices (); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Connect.lib.core/Settings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using core.audiamus.aux.diagn; 3 | using core.audiamus.booksdb; 4 | using core.audiamus.util; 5 | 6 | namespace core.audiamus.connect { 7 | public interface IConfigSettings { 8 | bool EncryptConfiguration { get; } 9 | } 10 | 11 | public interface IMultiPartSettings { 12 | bool MultiPartDownload { get; } 13 | } 14 | 15 | public interface IAuthorizeSettings { 16 | bool AutoRefresh { get; } 17 | } 18 | 19 | public interface IDownloadSettings : IMultiPartSettings, IAuthorizeSettings { 20 | event EventHandler ChangedSettings; 21 | 22 | bool AutoUpdateLibrary { get; } 23 | bool AutoOpenDownloadDialog { get; } 24 | bool IncludeAdultProducts { get; } 25 | bool HideUnavailableProducts { get; } 26 | bool KeepEncryptedFiles { get; } 27 | EDownloadQuality DownloadQuality { get; } 28 | string DownloadDirectory { get; } 29 | EInitialSorting InitialSorting { get; } 30 | } 31 | 32 | public interface IExportSettings { 33 | bool? ExportToAax { get; } 34 | [ToString (typeof (ToStringConverterPath))] 35 | string ExportDirectory { get; } 36 | } 37 | 38 | public abstract class SettingsBase { 39 | public event EventHandler ChangedSettings; 40 | public void OnChange () => ChangedSettings?.Invoke (this, EventArgs.Empty); 41 | } 42 | 43 | public class ConfigSettings : SettingsBase, IConfigSettings { 44 | private bool _encryptConfiguration = true; 45 | 46 | public bool EncryptConfiguration { 47 | get => _encryptConfiguration; 48 | set { 49 | _encryptConfiguration = value; 50 | OnChange (); 51 | } 52 | } 53 | } 54 | 55 | public class DownloadSettings : SettingsBase, IDownloadSettings { 56 | private EDownloadQualityReducedChoices _downloadQuality = EDownloadQualityReducedChoices.High; 57 | 58 | public bool AutoRefresh { get; set; } 59 | public bool AutoUpdateLibrary { get; set; } = true; 60 | public bool AutoOpenDownloadDialog { get; set; } 61 | public bool IncludeAdultProducts { get; set; } 62 | public bool HideUnavailableProducts { get; set; } 63 | public bool MultiPartDownload { get; set; } 64 | public bool KeepEncryptedFiles { get; set; } 65 | public EDownloadQuality DownloadQuality { 66 | get => _downloadQuality.ToFullChoices (); 67 | set => _downloadQuality = value.ToReducedChoices (); 68 | } 69 | public string DownloadDirectory { get; set; } 70 | public EInitialSorting InitialSorting { get; set; } 71 | public ProfileAliasKey Profile { get; set; } 72 | 73 | } 74 | 75 | public class ExportSettings : SettingsBase, IExportSettings { 76 | private bool? _exportToAax; 77 | private string _exportDirectory; 78 | 79 | public bool? ExportToAax { 80 | get => _exportToAax; 81 | set { 82 | _exportToAax = value; 83 | OnChange (); 84 | } 85 | } 86 | 87 | public string ExportDirectory { 88 | get => _exportDirectory; 89 | set { 90 | _exportDirectory = value; 91 | OnChange (); 92 | } 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Connect.lib.core/enums.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace core.audiamus.connect { 4 | 5 | public enum EInitialSorting { 6 | state_date, 7 | date, 8 | author_title, 9 | author_date, 10 | title_author 11 | } 12 | 13 | [Flags] 14 | enum ECheckFile { 15 | none = 0, 16 | deleteIfMissing = 1, 17 | relocatable = 2 18 | } 19 | 20 | public enum EBookLibInteract { 21 | none, 22 | checkFile 23 | } 24 | 25 | public enum EAuthorizeResult { 26 | none, 27 | invalidUrl, 28 | authorizationFailed, 29 | registrationFailed, 30 | removeFailed, 31 | succ, 32 | deregistrationFailed, 33 | removeProfileFailed, 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/AccountAliasForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Windows.Forms; 4 | using core.audiamus.aux.ex; 5 | using core.audiamus.aux.win.ex; 6 | 7 | namespace core.audiamus.connect.ui { 8 | public partial class AccountAliasForm : Form { 9 | private AccountAliasContext Context { get; } 10 | 11 | public AccountAliasForm (AccountAliasContext ctxt) { 12 | InitializeComponent (); 13 | 14 | if (ctxt is null) 15 | return; 16 | 17 | Context = ctxt; 18 | 19 | bool newAlias = !ctxt.Alias.IsNullOrWhiteSpace (); 20 | 21 | btnCancel.Visible = newAlias; 22 | 23 | //this.SetStartPositionCentered (); 24 | 25 | lblCaption.Text += $"\"{ctxt.CustomerName}\""; 26 | if (!newAlias) 27 | comboBox1.Items.Add ($"Account {ctxt.LocalId}"); 28 | else 29 | comboBox1.Items.Add (ctxt.Alias); 30 | comboBox1.Items.Add (ctxt.CustomerName); 31 | comboBox1.SelectedIndex = 0; 32 | } 33 | 34 | private void btnOk_Click (object sender, EventArgs e) { 35 | if (Context is not null) 36 | Context.Alias = comboBox1.Text.Trim (); 37 | DialogResult = DialogResult.OK; 38 | Close (); 39 | } 40 | 41 | private void comboBox1_TextUpdate (object sender, EventArgs e) { 42 | string text = comboBox1.Text.Trim (); 43 | bool enable = text.Length >= 3; 44 | 45 | uint crc = text.Checksum32 (); 46 | if (Context?.Hashes?.Contains (crc) ?? false) 47 | enable = false; 48 | if (!Context.Alias.IsNullOrWhiteSpace() && text == Context.Alias) 49 | enable = true; 50 | 51 | btnOk.Enabled = enable; 52 | } 53 | 54 | private void btnCancel_Click (object sender, EventArgs e) { 55 | Close (); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/AccountAliasForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/BookDataSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Linq; 5 | using core.audiamus.aux; 6 | using core.audiamus.aux.propgrid; 7 | using core.audiamus.booksdb; 8 | using R = core.audiamus.connect.ui.Properties.Resources; 9 | 10 | namespace core.audiamus.connect.ui { 11 | public class BookDataSource : BookDataSourceBase { 12 | public BookDataSource (Book book, IDownloadSettings settings) : base (book, settings) { } 13 | 14 | [GlobalizedProperty] 15 | public Image State { 16 | get { 17 | bool succ = __icons.TryGetValue (StateBacking, out var img); 18 | if (succ) { 19 | if (MultiState) 20 | img = imagePlus (img); 21 | return img; 22 | } else 23 | return R.ImgBlank; 24 | } 25 | } 26 | 27 | [Browsable (false)] 28 | public EConversionState StateBacking => getState (); 29 | 30 | public override DateTime? PurchaseDate => base.PurchaseDate; 31 | 32 | public override string Title => base.Title; 33 | 34 | public override string Author => base.Author; 35 | 36 | public override string Duration => base.Duration; 37 | 38 | [GlobalizedProperty] 39 | public int? Year { 40 | get { 41 | int? year = Book.ReleaseDate?.Date.Year; 42 | if (year.HasValue && year.Value == 2200) 43 | return null; 44 | return year; 45 | } 46 | } 47 | 48 | public override string Narrator => base.Narrator; 49 | 50 | [GlobalizedProperty] 51 | public string Series => Book.Series.FirstOrDefault ()?.ToString (); 52 | 53 | [GlobalizedProperty] 54 | [TypeConverter (typeof (BooleanYesNoConverter))] 55 | public bool? Adult => Book.AdultProduct; 56 | 57 | [GlobalizedProperty] 58 | public string Genre => Book.Ladders.FirstOrDefault ()?.ToString (); 59 | 60 | [GlobalizedProperty] 61 | public int? Parts => Book.Components.Count > 0 ? Book.Components.Count : null; 62 | 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/BookDataSourceBase.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Linq; 3 | using core.audiamus.booksdb; 4 | using core.audiamus.booksdb.ex; 5 | 6 | namespace core.audiamus.connect.ui { 7 | public abstract class BookDataSourceBase : DataSourceBase { 8 | 9 | [Browsable (false)] 10 | public Book Book => base.DataSource; 11 | 12 | public BookDataSourceBase (Book book, IDownloadSettings settings) : base (book) { 13 | Settings = settings; 14 | } 15 | 16 | //[GlobalizedProperty] 17 | //public virtual string SampleRate => SampleRateBacking.HasValue ? $"{SampleRateBacking.Value} Hz" : null; 18 | 19 | [Browsable (false)] 20 | public int? SampleRateBacking => Book.Codecs.MaxQuality()?.SampleRate; 21 | 22 | //[GlobalizedProperty] 23 | //public virtual string BitRate => BitRateBacking.HasValue ? $"{BitRateBacking.Value} kb/s" : null; 24 | 25 | [Browsable (false)] 26 | public int? BitRateBacking => Book.Codecs.MaxQuality()?.BitRate; 27 | 28 | 29 | public override string ToString () => $"\"{Book.Authors.FirstOrDefault()?.Name} - {Book.Title}\""; 30 | 31 | protected IDownloadSettings Settings { get; } 32 | 33 | protected bool MultiState { 34 | get { 35 | if (!Settings.MultiPartDownload || Book.Components.Count == 0) 36 | return false; 37 | return Book.Components 38 | .Select (c => c.Conversion.State) 39 | .Distinct () 40 | .Count () > 1; 41 | } 42 | } 43 | 44 | protected EConversionState getState () { 45 | if (Settings.MultiPartDownload && Book.Components.Count > 0) { 46 | var state = Book.Components 47 | .Select (c => c.Conversion.State) 48 | .Distinct () 49 | .Min (); 50 | return state; 51 | } else 52 | return Book.Conversion.State; 53 | } 54 | 55 | 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/BookLibDGVControl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/BookLibForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/BookPGA.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | using core.audiamus.aux; 5 | using core.audiamus.aux.ex; 6 | using core.audiamus.aux.propgrid; 7 | using core.audiamus.booksdb; 8 | 9 | namespace core.audiamus.connect.ui { 10 | public class BookPGA : BookDataSourceBase { 11 | public BookPGA (Book book, IDownloadSettings settings) : base (book, settings) { 12 | SetReadonly (EReadonly.all); 13 | } 14 | 15 | 16 | [PropertyOrder (1)] 17 | [GlobalizedProperty] 18 | [TypeConverter (typeof (EnumConverterRM))] 19 | public EConversionState State => getState(); 20 | 21 | [PropertyOrder (2)] 22 | public override string Title => base.Title; 23 | 24 | [PropertyOrder (3)] 25 | public override string Author => base.DataSource.MultiAuthors; 26 | 27 | [PropertyOrder (4)] 28 | public override string Duration => base.Duration; 29 | 30 | [PropertyOrder (5)] 31 | [GlobalizedProperty] 32 | [TypeConverter (typeof (BooleanYesNoConverter))] 33 | public bool? Unabridged => Book.Unabridged; 34 | 35 | [PropertyOrder (6)] 36 | [GlobalizedProperty] 37 | public string Language => Book.Language; 38 | 39 | [PropertyOrder (7)] 40 | [GlobalizedProperty] 41 | public DateTime? ReleaseDate => Book.ReleaseDate; 42 | 43 | [PropertyOrder (8)] 44 | public override string Narrator => base.DataSource.MultiNarrators; 45 | 46 | [PropertyOrder (9)] 47 | [GlobalizedProperty] 48 | public string Publisher => Book.PublisherName; 49 | 50 | [PropertyOrder (10)] 51 | [GlobalizedProperty] 52 | //[Editor (typeof (MultilineStringEditor), typeof (UITypeEditor))] 53 | public string Series => Book.Series.Select (l => l.ToString()).Combine(true); 54 | 55 | [PropertyOrder (11)] 56 | [GlobalizedProperty] 57 | [TypeConverter (typeof (BooleanYesNoConverter))] 58 | public bool? AdultProduct => Book.AdultProduct; 59 | 60 | [PropertyOrder (12)] 61 | [GlobalizedProperty] 62 | //[Editor (typeof (MultilineStringEditor), typeof (UITypeEditor))] 63 | public string Genres => Book.Ladders.Select (l => l.ToString()).Combine(true); 64 | 65 | [PropertyOrder (13)] 66 | [GlobalizedProperty] 67 | public string AverageRating => Book.AverageRating is null ? null : Book.AverageRating.Value.ToString("f1"); 68 | 69 | [PropertyOrder (14)] 70 | [GlobalizedProperty] 71 | [TypeConverter (typeof (EnumConverterRM))] 72 | public EDeliveryType? DeliveryType => Book.DeliveryType; 73 | 74 | [PropertyOrder (15)] 75 | [GlobalizedProperty] 76 | public int? Parts => Book.Components.Count > 0 ? Book.Components.Count : null; 77 | 78 | [PropertyOrder (16)] 79 | [GlobalizedProperty] 80 | public string FileSize => fileSize (fileSizeBytes ()); 81 | 82 | [PropertyOrder (17)] 83 | [GlobalizedProperty] 84 | public string SampleRate => SampleRateBacking.HasValue ? $"{SampleRateBacking.Value} Hz" : null; 85 | 86 | [PropertyOrder (18)] 87 | [GlobalizedProperty] 88 | public string BitRate => BitRateBacking.HasValue ? $"{BitRateBacking.Value} kb/s" : null; 89 | 90 | [PropertyOrder (19)] 91 | public override DateTime? PurchaseDate => base.PurchaseDate; 92 | 93 | public void OnUpdatedSettings (bool showAdultProduct) { 94 | PropertyCommands[nameof (AdultProduct)].Visible = showAdultProduct; 95 | } 96 | 97 | private long? fileSizeBytes () { 98 | if (Book.FileSizeBytes.HasValue) 99 | return Book.FileSizeBytes; 100 | else { 101 | long? sum = Book.Components?.Select (c => c.FileSizeBytes).Sum (); 102 | if (!sum.HasValue || sum.Value == 0) 103 | return null; 104 | return sum; 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Connect.ui.lib.core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0-windows 5 | true 6 | core.audiamus.connect.ui 7 | audiamus.connect.ui.core 8 | audiamus 9 | Copyright © 2021 - $([System.DateTime]::UtcNow.Year) audiamus ($([System.DateTime]::UtcNow.ToString("s"))) 10 | 0.13.0.0 11 | 0.13.0.0 12 | 13 | 14 | 15 | x64 16 | 17 | 18 | 19 | x64 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | True 33 | True 34 | Resources.resx 35 | 36 | 37 | 38 | 39 | 40 | ResXFileCodeGenerator 41 | Resources.Designer.cs 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/ConversionDataSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using core.audiamus.aux.ex; 5 | using core.audiamus.aux.propgrid; 6 | using core.audiamus.booksdb; 7 | using core.audiamus.booksdb.ex; 8 | using core.audiamus.common; 9 | using R = core.audiamus.connect.ui.Properties.Resources; 10 | 11 | namespace core.audiamus.connect.ui { 12 | class ConversionDataSource : DataSourceBase, IEquatable { 13 | 14 | [Browsable (false)] 15 | public Conversion Conversion => base.DataSource; 16 | 17 | 18 | public ConversionDataSource (Conversion conv) : base (conv) { } 19 | 20 | [GlobalizedProperty] 21 | public Image State { 22 | get { 23 | bool succ = __icons.TryGetValue (StateBacking, out var img); 24 | if (succ) 25 | return img; 26 | else 27 | return R.ImgBlank; 28 | } 29 | } 30 | 31 | [Browsable (false)] 32 | public EConversionState StateBacking => Conversion.State; 33 | 34 | 35 | public override string Title => title (); 36 | 37 | public override string Author => base.Author; 38 | 39 | [GlobalizedProperty] 40 | public string FileSize => fileSize (FileSizeBacking); 41 | 42 | public override string Duration => base.Duration; 43 | 44 | [GlobalizedProperty] 45 | public int? Year { 46 | get { 47 | int? year = Conversion.ReleaseDate?.Date.Year; 48 | if (year.HasValue && year.Value == 2200) 49 | return null; 50 | return year; 51 | } 52 | } 53 | 54 | public override string Narrator => Conversion.Narrator; 55 | 56 | [Browsable (false)] 57 | public int? SampleRateBacking => rateBacking (a => a?.SampleRate); 58 | 59 | [Browsable (false)] 60 | public int? BitRateBacking => rateBacking (a => a?.BitRate); 61 | 62 | 63 | [GlobalizedProperty] 64 | public string SampleRate => SampleRateBacking.HasValue ? $"{SampleRateBacking.Value} Hz" : null; 65 | 66 | [GlobalizedProperty] 67 | public string BitRate => BitRateBacking.HasValue ? $"{BitRateBacking.Value} kb/s" : null; 68 | 69 | [GlobalizedProperty] 70 | public override DateTime? PurchaseDate => base.PurchaseDate; 71 | 72 | public bool Equals (ConversionDataSource other) => Conversion.Equals(other.Conversion); 73 | public override bool Equals (object obj) => Equals (obj as ConversionDataSource); 74 | public override int GetHashCode () => Conversion.GetHashCode (); 75 | 76 | 77 | private string title () { 78 | if (!base.Title.IsNullOrWhiteSpace ()) 79 | return base.Title; 80 | var comp = DataSource.Component; 81 | if (comp is null) 82 | return null; 83 | return $"{comp.Book.Title} {R.Part} {comp.PartNumber}"; 84 | } 85 | 86 | private int? rateBacking (Func getProp) { 87 | int? rate = getProp (Conversion); 88 | 89 | if (rate.HasValue) 90 | return rate; 91 | if (Conversion.Book is null) 92 | return getRate (Conversion.Component.Book, getProp); 93 | else 94 | return getRate (Conversion.Book, getProp); 95 | } 96 | 97 | private static int? getRate(Book book, Func getProp) { 98 | int? rate = getProp (book); 99 | if (rate is null) 100 | return getProp(book.Codecs.MaxQuality()); 101 | else 102 | return rate; 103 | 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/ConvertDGVControl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | 61 | 17, 17 62 | 63 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/DataSourceBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using core.audiamus.aux.ex; 6 | using core.audiamus.aux.propgrid; 7 | using core.audiamus.booksdb; 8 | using core.audiamus.common; 9 | using R = core.audiamus.connect.ui.Properties.Resources; 10 | 11 | namespace core.audiamus.connect.ui { 12 | public abstract class DataSourceBase : BasePropertyGridAdapter 13 | where T: IBookMeta 14 | { 15 | protected static readonly Dictionary __icons = 16 | new Dictionary { 17 | { EConversionState.unknown, R.ImgGlobeFailed }, 18 | { EConversionState.remote, R.ImgGlobe }, 19 | { EConversionState.download, R.ImgGlobeDown }, 20 | { EConversionState.license_granted, R.ImgKey }, 21 | { EConversionState.license_denied, R.ImgKeyDenied }, 22 | { EConversionState.downloading, R.ImgDown }, 23 | { EConversionState.download_error, R.ImgDownBroken }, 24 | { EConversionState.local_locked, R.ImgLocked }, 25 | { EConversionState.unlocking, R.ImgUnlocking }, 26 | { EConversionState.unlocking_failed, R.ImgUnlockingFailed }, 27 | { EConversionState.local_unlocked, R.ImgUnlocked }, 28 | { EConversionState.exported, R.ImgCheckMauve }, 29 | { EConversionState.converting, R.ImgRight }, 30 | { EConversionState.converted, R.ImgCheck }, 31 | { EConversionState.converted_unknown, R.ImgCheckGrey }, 32 | { EConversionState.conversion_error, R.ImgRightFailed }, 33 | }; 34 | 35 | protected DataSourceBase (T datasource) : base (datasource) { 36 | } 37 | 38 | protected static Image imagePlus (Image image) { 39 | Bitmap bitmap = new Bitmap (image); 40 | using var gr = Graphics.FromImage (bitmap); 41 | gr.DrawImage (R.ImgPlus, 0, 0); 42 | return bitmap; 43 | } 44 | 45 | [GlobalizedProperty] 46 | public virtual string Title => DataSource.Title; 47 | 48 | [GlobalizedProperty] 49 | public virtual string Author => DataSource.Author; 50 | 51 | [GlobalizedProperty] 52 | public virtual string Duration => 53 | DurationBacking?.ToStringHMS (); 54 | 55 | [Browsable (false)] 56 | public TimeSpan? DurationBacking => DataSource.RunTimeLengthSeconds.HasValue ? 57 | TimeSpan.FromSeconds (DataSource.RunTimeLengthSeconds.Value) : null; 58 | 59 | [Browsable (false)] 60 | public virtual long? FileSizeBacking => DataSource.FileSizeBytes; 61 | 62 | [GlobalizedProperty] 63 | public virtual string Narrator => DataSource.Narrator; 64 | 65 | [GlobalizedProperty] 66 | public virtual DateTime? PurchaseDate => DataSource.PurchaseDate?.Date; 67 | 68 | protected string fileSize (long ? size) => size is null ? null : $"{size.Value / (1024 * 1024)} MB"; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Events.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using core.audiamus.booksdb; 4 | 5 | namespace core.audiamus.connect.ui { 6 | public class BookEventArgs : EventArgs { 7 | public IEnumerable Books { get; } 8 | 9 | public BookEventArgs (IEnumerable books) => Books = books; 10 | } 11 | 12 | public delegate void BookSelectionChangedEventHandler (object sender, BookEventArgs args); 13 | 14 | public class ConversionEventArgs : EventArgs { 15 | public Conversion Conversion { get; } 16 | 17 | public ConversionEventArgs (Conversion conversion) => Conversion = conversion; 18 | } 19 | 20 | public delegate void ConversionUpdatedEventHandler (object sender, ConversionEventArgs args); 21 | 22 | public class BoolEventArgs : EventArgs { 23 | public bool Value { get; } 24 | 25 | public BoolEventArgs (bool value) => Value = value; 26 | } 27 | 28 | public delegate void BoolEventHandler (object sender, BoolEventArgs args); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Linq; 3 | using core.audiamus.booksdb; 4 | 5 | namespace core.audiamus.connect.ui { 6 | public static class Extensions { 7 | 8 | public static int IndexOf (this BindingList bindingList, Book dataItem) { 9 | int idx = bindingList.IndexOf (bindingList.FirstOrDefault (k => ReferenceEquals (k.DataSource, dataItem))); 10 | return idx; 11 | } 12 | 13 | internal static int IndexOf (this BindingList bindingList, Conversion dataItem) { 14 | int idx = bindingList.IndexOf (bindingList.FirstOrDefault (k => ReferenceEquals (k.DataSource, dataItem))); 15 | return idx; 16 | } 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/InternalsVisible.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo ("BookLibConnect.FormsTest")] 4 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/ManageProfilesForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/NewProfileForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | 61 | 17, 17 62 | 63 | 64 | Sign in with your Amazon or Audible credentials in the web browser. 65 | Solve any captchas. 66 | Confirm your identity, if Amazon wants 2-factor-authentication. 67 | On success, you will see a webpage which claims that the requested page is not available. 68 | However, this is the page you want. 69 | Copy the URL of that page into the text box below. 70 | 71 | -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/blank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/blank.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/check.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/checkGrey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/checkGrey.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/checkMauve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/checkMauve.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/down.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/downBroken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/downBroken.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/globe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/globe.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/globeDown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/globeDown.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/globeFailed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/globeFailed.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/license.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/license.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/licenseDenied.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/licenseDenied.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/locked.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/plus.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/question.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/redx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/redx.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/right.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/rightFailed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/rightFailed.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/unlocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/unlocked.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/unlocking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/unlocking.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/Resources/unlockingFailed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/Connect.ui.lib.core/Resources/unlockingFailed.png -------------------------------------------------------------------------------- /src/Connect.ui.lib.core/TypeConvertersRM.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using core.audiamus.aux; 3 | using core.audiamus.aux.ex; 4 | 5 | namespace core.audiamus.connect.ui { 6 | class EnumConverterRM : EnumConverter 7 | where TEnum : struct, Enum { 8 | 9 | public EnumConverterRM () { 10 | ResourceManager = this.GetDefaultResourceManager (); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/InnoSetup/BookLibConnect setup.iss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/BookLibConnect/865f3bc0eee88dd408864ec25e14750dabc5e918/src/InnoSetup/BookLibConnect setup.iss -------------------------------------------------------------------------------- /src/PropGridLib.core/Attributes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace core.audiamus.aux.propgrid { 4 | [AttributeUsage (AttributeTargets.Property, AllowMultiple = false, Inherited = true)] 5 | public class GlobalizedPropertyAttribute : Attribute { 6 | public string NameTag { get; set; } 7 | public string DescriptionTag { get; set; } 8 | public string CategoryTag { get; set; } 9 | public string ResourceTable { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/PropGridLib.core/PropGridLib.core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0-windows 5 | true 6 | core.audiamus.aux.propgrid 7 | audiamus.aux.propgrid.core 8 | audiamus 9 | Copyright © 2021 - $([System.DateTime]::UtcNow.Year) audiamus ($([System.DateTime]::UtcNow.ToString("s"))) 10 | 0.2.0.0 11 | 0.2.0.0 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/PropGridLib.core/PropertyGridExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Reflection; 5 | using System.Windows.Forms; 6 | 7 | namespace core.audiamus.aux.propgrid { 8 | public static class PropertyGridExtensions { 9 | 10 | 11 | /// 12 | /// Moves the property Grid's splitter bar over to fit the width 13 | /// of the longest display name string + padding 14 | /// 15 | /// 16 | /// The property Grid whose splitter bar is to be moved 17 | /// Right padding to include with longest display name width 18 | public static void MoveSplitterToLongestDisplayName (this PropertyGrid propertyGrid, int iPadding) { 19 | try { 20 | 21 | if (propertyGrid.SelectedObject is null) 22 | return; 23 | 24 | Size longestTextSize = new Size (); 25 | if (propertyGrid.SelectedObject is DynamicTypeDescriptor dtd) { 26 | var propdescs = dtd.GetProperties (new[] { new BrowsableAttribute (true) }); 27 | foreach (PropertyDescriptor propdesc in propdescs) { 28 | var browsable = propdesc.Attributes[typeof (BrowsableAttribute)] as BrowsableAttribute; 29 | if (!(browsable?.Browsable ?? false)) 30 | continue; 31 | string displayName = propdesc.DisplayName; 32 | Size textSize = TextRenderer.MeasureText (displayName, propertyGrid.Font); 33 | if (textSize.Width > longestTextSize.Width) { 34 | longestTextSize = textSize; 35 | } 36 | } 37 | } 38 | 39 | propertyGrid.MoveSplitterTo (longestTextSize.Width + 17 + iPadding); 40 | } catch (Exception) { 41 | } 42 | } 43 | 44 | /// 45 | /// Gets the width of the left column. 46 | /// 47 | /// The property grid. 48 | /// 49 | /// The width of the left column. 50 | /// 51 | public static int GetInternalLabelWidth (this PropertyGrid propertyGrid) { 52 | object gridView = getPropertyGridView (propertyGrid); 53 | 54 | PropertyInfo pi = gridView.GetType ().GetProperty ( 55 | "InternalLabelWidth", BindingFlags.NonPublic | BindingFlags.Instance); 56 | return (int)pi.GetValue (gridView); 57 | } 58 | 59 | /// 60 | /// Moves the property Grid's splitter bar to given position 61 | /// 62 | /// 63 | /// 64 | public static void MoveSplitterTo (this PropertyGrid propertyGrid, int position) { 65 | object propertyGridView = getPropertyGridView (propertyGrid); 66 | 67 | MethodInfo mi = propertyGridView.GetType ().GetMethod ( 68 | "MoveSplitterTo", BindingFlags.NonPublic | BindingFlags.Instance); 69 | mi.Invoke (propertyGridView, new object[] { position }); 70 | } 71 | 72 | 73 | /// 74 | /// Gets the (private) PropertyGridView instance. 75 | /// 76 | /// The property grid. 77 | /// The PropertyGridView instance. 78 | private static object getPropertyGridView (this PropertyGrid propertyGrid) { 79 | MethodInfo mi = typeof (PropertyGrid).GetMethod ( 80 | "GetPropertyGridView", BindingFlags.NonPublic | BindingFlags.Instance); 81 | return mi.Invoke (propertyGrid, Array.Empty ()); 82 | } 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/PropGridLib.core/PropertySorter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.ComponentModel; 4 | 5 | namespace core.audiamus.aux.propgrid { 6 | public class PropertySorter : ExpandableObjectConverter { 7 | #region Methods 8 | public override bool GetPropertiesSupported(ITypeDescriptorContext context) { 9 | return true; 10 | } 11 | 12 | public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) { 13 | // 14 | // This override returns a list of properties in order 15 | // 16 | PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(value, attributes); 17 | ArrayList orderedProperties = new ArrayList(); 18 | foreach (PropertyDescriptor pd in pdc) { 19 | Attribute attribute = pd.Attributes[typeof(PropertyOrderAttribute)]; 20 | if (attribute != null) { 21 | // 22 | // If the attribute is found, then create an pair object to hold it 23 | // 24 | PropertyOrderAttribute poa = (PropertyOrderAttribute)attribute; 25 | orderedProperties.Add(new PropertyOrderPair(pd.Name, poa.Order)); 26 | } else { 27 | // 28 | // If no order attribute is specifed then given it an order of 0 29 | // 30 | orderedProperties.Add(new PropertyOrderPair(pd.Name, 0)); 31 | } 32 | } 33 | // 34 | // Perform the actual order using the value PropertyOrderPair classes 35 | // implementation of IComparable to sort 36 | // 37 | orderedProperties.Sort(); 38 | // 39 | // Build a string list of the ordered names 40 | // 41 | ArrayList propertyNames = new ArrayList(); 42 | foreach (PropertyOrderPair pop in orderedProperties) { 43 | propertyNames.Add(pop.Name); 44 | } 45 | // 46 | // Pass in the ordered list for the PropertyDescriptorCollection to sort by 47 | // 48 | return pdc.Sort((string[])propertyNames.ToArray(typeof(string))); 49 | } 50 | #endregion 51 | } 52 | 53 | #region Helper Class - PropertyOrderAttribute 54 | [AttributeUsage(AttributeTargets.Property)] 55 | public class PropertyOrderAttribute : Attribute { 56 | // 57 | // Simple attribute to allow the order of a property to be specified 58 | // 59 | private int _order; 60 | public PropertyOrderAttribute(int order) { 61 | _order = order; 62 | } 63 | 64 | public int Order { 65 | get { 66 | return _order; 67 | } 68 | } 69 | } 70 | #endregion 71 | 72 | #region Helper Class - PropertyOrderPair 73 | public class PropertyOrderPair : IComparable { 74 | private int _order; 75 | private string _name; 76 | public string Name { 77 | get { 78 | return _name; 79 | } 80 | } 81 | 82 | public PropertyOrderPair(string name, int order) { 83 | _order = order; 84 | _name = name; 85 | } 86 | 87 | public int CompareTo(object obj) { 88 | // 89 | // Sort the pair objects by ordering by order value 90 | // Equal values get the same rank 91 | // 92 | int otherOrder = ((PropertyOrderPair)obj)._order; 93 | if (otherOrder == _order) { 94 | // 95 | // If order not specified, sort by name 96 | // 97 | string otherName = ((PropertyOrderPair)obj)._name; 98 | return string.Compare(_name, otherName); 99 | } else if (otherOrder > _order) { 100 | return -1; 101 | } 102 | return 1; 103 | } 104 | } 105 | #endregion 106 | } -------------------------------------------------------------------------------- /src/SystemMgmt.core/HardwareId.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Management; 3 | 4 | namespace core.audiamus.sysmgmt { 5 | /// 6 | /// http://jai-on-asp.blogspot.com/2010/03/finding-hardware-id-of-computer.html 7 | /// 8 | public static class HardwareId { 9 | public static string GetCpuId () { 10 | //ManagementObjectCollection mbsList = null; 11 | try { 12 | ManagementObjectSearcher mbs = new ManagementObjectSearcher ("Select * From Win32_processor"); 13 | ManagementObjectCollection mbsList = mbs.Get (); 14 | string id = string.Empty; 15 | foreach (ManagementObject mo in mbsList) { 16 | id = mo["ProcessorID"].ToString (); 17 | } 18 | return id; 19 | } catch (Exception) { 20 | return string.Empty; 21 | } 22 | } 23 | 24 | public static string GetDiskId () { 25 | try { 26 | ManagementObject dsk = new ManagementObject (@"win32_logicaldisk.deviceid=""c:"""); 27 | dsk.Get (); 28 | string id = dsk["VolumeSerialNumber"].ToString (); 29 | return id; 30 | } catch (Exception) { 31 | return string.Empty; 32 | } 33 | } 34 | 35 | public static string GetMotherboardId () { 36 | return MotherboardInfo.SerialNumber; 37 | } 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/SystemMgmt.core/SystemMgmt.core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | core.audiamus.sysmgmt 6 | audiamus.sysmgmt.core 7 | audiamus 8 | 1.2.0.0 9 | 1.2.0.0 10 | Copyright © 2021 - $([System.DateTime]::UtcNow.Year) audiamus ($([System.DateTime]::UtcNow.ToString("s"))) 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/TreeDecomposition.core/CustomAttributes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace core.audiamus.aux.diagn { 5 | 6 | /// 7 | /// An attribute intended to be used as a custom format string in text serialization. 8 | /// 9 | /// 10 | [AttributeUsage (AttributeTargets.Property)] 11 | public class TextFormatAttribute : Attribute { 12 | public readonly string Format; 13 | 14 | public TextFormatAttribute (string format) => Format = format; 15 | } 16 | 17 | /// 18 | /// An attribute intended to convey a custom ToString() method. 19 | /// Given type must be derived from . 20 | /// Optional second parameter to be interpreted as a format specification. 21 | /// 22 | /// 23 | [AttributeUsage (AttributeTargets.Property)] 24 | public class ToStringAttribute : Attribute { 25 | static readonly Dictionary __converters = new Dictionary (); 26 | 27 | public readonly ToStringConverter Converter; 28 | public readonly string Format; 29 | 30 | public ToStringAttribute (Type type, string format = null) { 31 | if (typeof (ToStringConverter).IsAssignableFrom (type)) { 32 | lock (__converters) { 33 | bool succ = __converters.TryGetValue (type, out var converter); 34 | if (succ) 35 | Converter = converter; 36 | else 37 | try { 38 | Converter = (ToStringConverter)Activator.CreateInstance (type); 39 | __converters.Add (type, Converter); 40 | } catch (Exception) { } 41 | } 42 | } 43 | Format = format; 44 | } 45 | } 46 | 47 | /// 48 | /// An attribute similar to , 49 | /// but intended to be used with collection items. 50 | /// 51 | /// 52 | [AttributeUsage (AttributeTargets.Property)] 53 | public class DisplayItemNameAttribute : Attribute { 54 | public readonly string Name; 55 | 56 | public DisplayItemNameAttribute (string name) => Name = name; 57 | } 58 | 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/TreeDecomposition.core/Enums.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | namespace core.audiamus.aux.diagn { 5 | 6 | /// 7 | /// Flags to control dump output 8 | /// 9 | [Flags] 10 | public enum EDumpFlags { 11 | none = 0, 12 | 13 | /// 14 | /// Add a counter to each item in an enumeration 15 | /// 16 | withItmCnt = 1, 17 | 18 | /// 19 | /// Include properties with null values 20 | /// 21 | inclNullVals = 2, 22 | 23 | /// 24 | /// Include property description, 25 | /// 26 | inclDesc = 4, 27 | 28 | /// 29 | /// Description above property, if included. Behind property by default. 30 | /// 31 | descOnTop = 8, 32 | 33 | /// 34 | /// Include type description, 35 | /// 36 | inclTypeDesc = 16, 37 | 38 | /// 39 | /// Include description in enumerations 40 | /// 41 | inclDescInEnum = 32, 42 | 43 | /// 44 | /// Inherit attributes defined for properities in base interfaces, for recognized attributes 45 | /// 46 | inherInterfaceAttribs = 64, 47 | 48 | /// 49 | /// Group properties by implemented interfaces and their hierarchy 50 | /// 51 | byInterface = 128, 52 | 53 | /// 54 | /// Include grouping by interface for types further down the hierarchy 55 | /// 56 | byInterfaceNestedTypes = 256, 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/TreeDecomposition.core/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace core.audiamus.aux.diagn { 4 | /// 5 | /// Interface for custom primitive types, to be used with 6 | /// 7 | public interface IPrimitiveTypes { 8 | 9 | /// 10 | /// Determines whether the specified generic type is regarded as a custom primitive type. 11 | /// 12 | /// generic type 13 | bool IsPrimitiveType (); 14 | 15 | 16 | /// 17 | /// Determines whether the specified type is regarded as a custom primitive type. 18 | /// 19 | /// The type to be checked. 20 | bool IsPrimitiveType (Type type); 21 | 22 | /// 23 | /// Returns a that represents this instance, 24 | /// if registered as a custom primitive type. Type-safe variant. 25 | /// 26 | /// generic type 27 | /// The value. 28 | /// 29 | /// A that represents this instance or null. 30 | /// 31 | string ToString (T val); 32 | 33 | /// 34 | /// Returns a that represents this instance, 35 | /// if registered as a custom primitive type. Type deduction variant. 36 | /// 37 | /// The value. 38 | /// 39 | /// A that represents this instance or null. 40 | /// 41 | string ToString (object val); 42 | 43 | /// 44 | /// Returns a that represents this instance, 45 | /// if registered as a custom primitive type. Non-type-safe variant. 46 | /// 47 | /// generic type 48 | /// The value. 49 | /// 50 | /// A that represents this instance. 51 | /// 52 | string ToString (object val); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/TreeDecomposition.core/ToStringConverter.cs: -------------------------------------------------------------------------------- 1 | namespace core.audiamus.aux.diagn { 2 | public abstract class ToStringConverter { 3 | public abstract string ToString (object o, string format = null); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/TreeDecomposition.core/TreeDecomposition.core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | core.core.audiamus.aux.diagn 6 | audiamus.aux.treedecomp.core 7 | audiamus 8 | 2.1.0.0 9 | 2.1.0.0 10 | Copyright © 2019 - $([System.DateTime]::UtcNow.Year) audiamus ($([System.DateTime]::UtcNow.ToString("s"))) 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/TreeDecomposition.core/TreeDecompositionExtension.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | 4 | namespace core.audiamus.aux.diagn { 5 | /// 6 | /// 7 | /// 8 | public static class TreeDecompositionExtension { 9 | 10 | /// 11 | /// Dumps the specified object as a text tree to a string, 12 | /// without additional primitive types. 13 | /// 14 | /// The object to dump. 15 | /// Output modifier flags. 16 | /// The optional caption for this indentation level. 17 | /// 18 | /// Text tree 19 | /// 20 | public static string Dump (this object o, EDumpFlags flags = default, string caption = null) { 21 | using (var sw = new StringWriter ()) { 22 | o.Dump (sw, new Indent (), flags, caption); 23 | return sw.ToString (); 24 | } 25 | } 26 | 27 | /// 28 | /// Dumps the specified object as a text tree to the specified , 29 | /// without additional primitive types. 30 | /// 31 | /// The object to dump. 32 | /// The TextWriter output. 33 | /// The indentation. 34 | /// Output modifier flags. 35 | /// The optional caption for this indentation level. 36 | public static void Dump (this object o, TextWriter tw, Indent ind = null, EDumpFlags flags = default, string caption = null) => 37 | TreeDecomposition.Default.Dump (o, tw, ind ?? new Indent (), flags, caption); 38 | 39 | /// 40 | /// Dumps the specified object as a text tree to a string, 41 | /// allowing additional user provided primitive types. 42 | /// 43 | /// Additional primitive types, implementing 44 | /// The object to dump. 45 | /// Output modifier flags. 46 | /// The optional caption for this indentation level. 47 | /// Text tree 48 | public static string Dump (this object o, EDumpFlags flags, string caption = null) 49 | where T : IPrimitiveTypes, new() 50 | { 51 | using (var sw = new StringWriter ()) { 52 | o.Dump (sw, new Indent (), flags, caption); 53 | return sw.ToString (); 54 | } 55 | } 56 | 57 | /// 58 | /// Dumps the specified object as a text tree to the specified , 59 | /// allowing additional user provided primitive types. 60 | /// 61 | /// Additional primitive types, implementing 62 | /// The object to dump. 63 | /// The TextWriter output. 64 | /// The indentation. 65 | /// Output modifier flags. 66 | /// The optional caption for this indentation level. 67 | public static void Dump (this object o, TextWriter tw, Indent ind = null, EDumpFlags flags = default, string caption = null) 68 | where T : IPrimitiveTypes, new() => 69 | TreeDecomposition.Default.Dump (o, tw, ind ?? new Indent (), flags, caption); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/TreeDecomposition.core/TypeExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace core.audiamus.aux.diagn { 7 | static class TypeExtension { 8 | 9 | public static IEnumerable> GetInterfaceHierarchy (this Type root) { 10 | var leavesDict = new Dictionary> (); 11 | findLeaves (root, new List (), leavesDict); 12 | List> list = sort (leavesDict); 13 | return list; 14 | } 15 | 16 | public static string ToHierarchyString (this IEnumerable path) { 17 | var sb = new StringBuilder (); 18 | foreach (var t in path) { 19 | if (sb.Length > 0) 20 | sb.Append (':'); 21 | sb.Append (t.Name); 22 | } 23 | return sb.ToString (); 24 | } 25 | 26 | private static void findLeaves (Type type, IList path, IDictionary> leaves) { 27 | if (type.IsInterface) { 28 | path.Add (type); 29 | bool succ = leaves.TryGetValue (type, out var p); 30 | if (!succ || path.Count > p.Count) 31 | leaves[type] = path.ToList (); 32 | } 33 | 34 | var ifcTypes = type.GetInterfaces (); 35 | foreach (var ifcType in ifcTypes) 36 | findLeaves (ifcType, path.ToList(), leaves); 37 | 38 | } 39 | 40 | private static List> sort (Dictionary> leavesDict) { 41 | var rawlist = leavesDict.Select (kvp => kvp.Value).OrderBy (k => k.Count).ToList (); 42 | var list = new List> (); 43 | 44 | while (rawlist.Count () > 0) { 45 | var path = rawlist.Last (); 46 | rawlist.RemoveAt (rawlist.Count - 1); 47 | list.Add (path); 48 | if (path.Count < 2) 49 | continue; 50 | var p = path.ToList (); 51 | while (p.Count > 1) { 52 | p.RemoveAt (p.Count - 1); 53 | Type deriv = p[p.Count - 1]; 54 | var dpath = rawlist.Where (k => k.Last () == deriv).FirstOrDefault (); 55 | if (dpath is null) 56 | break; 57 | rawlist.Remove (dpath); 58 | list.Add (dpath); 59 | } 60 | } 61 | 62 | return list; 63 | } 64 | } 65 | } 66 | --------------------------------------------------------------------------------