├── LICENSE ├── README.md ├── res ├── Cover.de.png ├── Cover.png ├── Details.de.png ├── Details.png ├── Main-progr.de.png ├── Main-progr.png ├── Preview.de.png ├── Preview.png ├── Screenshots.md ├── Settings.de.png ├── Settings.png ├── Settings2.de.png ├── Settings2.png ├── Settings3.de.png ├── Settings3.png ├── Settings4.de.png ├── Settings4.png ├── Settings5.de.png ├── Settings5.png ├── Setup.dat └── Setup.json └── src ├── AAX Audio Converter.sln ├── AaxAudioConverter ├── AaxAudioConverter.csproj ├── AaxAudioConverter.de.odt ├── AaxAudioConverter.latest.de.rtf ├── AaxAudioConverter.latest.rtf ├── AaxAudioConverter.odt ├── AaxFileItemEx.cs ├── AboutForm.Designer.cs ├── AboutForm.cs ├── AboutForm.de.resx ├── AboutForm.resx ├── ActivationCodeForm.Designer.cs ├── ActivationCodeForm.cs ├── ActivationCodeForm.de.resx ├── ActivationCodeForm.resx ├── App.config ├── FFmpegLocationForm.Designer.cs ├── FFmpegLocationForm.cs ├── FFmpegLocationForm.de.resx ├── FFmpegLocationForm.resx ├── FileAssoc.cs ├── FileDetailsForm.Designer.cs ├── FileDetailsForm.cs ├── FileDetailsForm.de.resx ├── FileDetailsForm.resx ├── FileItemForm.cs ├── FodyWeavers.xml ├── GenresForm.Designer.cs ├── GenresForm.cs ├── GenresForm.de.resx ├── GenresForm.resx ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.de.resx ├── MainForm.resx ├── PGANaming.cs ├── PGANaming.de.resx ├── PGANaming.resx ├── PerformanceHandler.cs ├── PreviewForm.Designer.cs ├── PreviewForm.cs ├── PreviewForm.de.resx ├── PreviewForm.resx ├── Program.cs ├── ProgressProcessor.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.de.resx │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Resources.cs ├── Resources │ ├── added.png │ ├── audio.ico │ ├── audio.png │ ├── blank.png │ ├── hidden features de.png │ └── hidden features en.png ├── Settings.cs ├── SettingsForm.Designer.cs ├── SettingsForm.cs ├── SettingsForm.de.resx ├── SettingsForm.resx ├── StartupTipForm.Designer.cs ├── StartupTipForm.cs ├── StartupTipForm.de.resx ├── StartupTipForm.resx ├── TypeConvertersRM.cs ├── WhatsNewForm.Designer.cs ├── WhatsNewForm.cs ├── WhatsNewForm.de.resx ├── WhatsNewForm.resx ├── app.manifest └── packages.config ├── AaxAudioConverterLib ├── AaxAudioConverter.cs ├── AaxAudioConverter.nested.cs ├── AaxAudioConverterLib.csproj ├── AaxFileCopier.cs ├── AaxFileItem.cs ├── ActivationCode.cs ├── ActivationCodeApp.cs ├── ActivationCodeRegistry.cs ├── AudibleAppContentMetadata.cs ├── AudibleAppSimsBySeries.cs ├── AudioMeta.cs ├── Book.Part.cs ├── Book.Progress.cs ├── Book.cs ├── CallbackWrapper.cs ├── ChainPunctuation.cs ├── Chapter.cs ├── ChapteredTracks.cs ├── ContentMetaDataJson.cs ├── ContentMetadata.json.cs ├── CustomTagFileNames.cs ├── Enums.cs ├── Extensions.cs ├── ExtraMetaFiles.cs ├── FFMetaData.cs ├── FFmpeg.cs ├── FileEx.cs ├── FixAtomESDS.cs ├── Interfaces.cs ├── OnlineUpdate.cs ├── ProgressMessage.cs ├── Properties │ └── AssemblyInfo.cs ├── ResourceInterface.cs ├── SeriesTitles.json.cs ├── SettingsInterface.cs ├── SimsBySeries.json.cs ├── TagAndFileNamingHelper.Numbers.cs ├── TagAndFileNamingHelper.cs ├── ThreadProgress.cs ├── TimeInterval.cs ├── ToStringConverters.cs ├── Track.cs ├── UpdatePackageInfo.cs ├── app.config └── packages.config ├── AuxLib ├── ApplEnv.cs ├── ArgParser.cs ├── AuxLib.csproj ├── BigEndianReader.cs ├── BooleanYesNoConverter.cs ├── ChainPunctuation.cs ├── DefaultSettings.cs ├── Encoding.cs ├── EnumChainTypeConverter.cs ├── EnumConverter.cs ├── EnumUtil.cs ├── ExtensionMethods.cs ├── IInteractionCallback.cs ├── Indent.cs ├── InteractionCallback.cs ├── InteractionMessage.cs ├── Interfaces.cs ├── LocalFileSettingsProvider.cs ├── Logging.cs ├── ProcessHost.cs ├── ProcessList.cs ├── Properties │ └── AssemblyInfo.cs ├── ResourceGuard.cs ├── ResourceManagerEx.cs ├── Singleton.cs └── Temp.cs ├── AuxWin32Lib ├── FileAssociation.cs ├── Properties │ └── AssemblyInfo.cs ├── Win32FileIO.cs └── auxWin32Lib.csproj ├── AuxWinLib ├── AuxWinLib.csproj ├── ComboBoxEnumAdapter.cs ├── ControlExPathEllipsis.cs ├── Culture.cs ├── DialogBox │ ├── AssemblyInfo.cs │ ├── AuxWin.DialogBox.csproj │ ├── CbtHook.cs │ ├── DialogBox.cs │ ├── Win32API.cs │ ├── WindowsHook.cs │ └── WndProcRetHook.cs ├── InteractionCallbackHandler.cs ├── ListViewColumnSorter.cs ├── Properties │ └── AssemblyInfo.cs ├── RtfBuilder.cs ├── SystemMenu.cs └── VerticalProgressBar.cs ├── InnoSetup └── AaxAudioConverter setup.iss ├── PerfLib ├── CpuUsage.cs ├── PerfCallback.cs ├── PerfLib.csproj ├── PerformanceMonitor.cs ├── ProcessCpuCounter.cs └── Properties │ └── AssemblyInfo.cs ├── PropGridLib ├── Attributes.cs ├── BasePropertyGridAdapter.cs ├── Descriptor.cs ├── DynamicProperty.cs ├── PropGridLib.csproj ├── Properties │ └── AssemblyInfo.cs └── PropertySorter.cs └── TreeDecomposition ├── AbstractPrimitiveTypes.cs ├── CustomAttributes.cs ├── Enums.cs ├── Interfaces.cs ├── Properties └── AssemblyInfo.cs ├── ToStringConverter.cs ├── TreeDecomposition.cs ├── TreeDecomposition.csproj ├── TreeDecompositionExtension.cs └── TypeExtension.cs /res/Cover.de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Cover.de.png -------------------------------------------------------------------------------- /res/Cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Cover.png -------------------------------------------------------------------------------- /res/Details.de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Details.de.png -------------------------------------------------------------------------------- /res/Details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Details.png -------------------------------------------------------------------------------- /res/Main-progr.de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Main-progr.de.png -------------------------------------------------------------------------------- /res/Main-progr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Main-progr.png -------------------------------------------------------------------------------- /res/Preview.de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Preview.de.png -------------------------------------------------------------------------------- /res/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Preview.png -------------------------------------------------------------------------------- /res/Screenshots.md: -------------------------------------------------------------------------------- 1 | |English 2 | |--------- 3 | |Main window 4 | |![](Cover.png?raw=true) 5 | |Main window, conversion in progress 6 | |![](Main-progr.png?raw=true) 7 | |Book details (Meta info) 8 | |![](Details.png?raw=true) 9 | |Preview 10 | |![](Preview.png?raw=true) 11 | |Settings General 12 | |![](Settings.png?raw=true) 13 | |Settings Folder structure 14 | |![](Settings2.png?raw=true) 15 | |Settings Conversion 16 | |![](Settings3.png?raw=true) 17 | |Settings Chapters 18 | |![](Settings4.png?raw=true) 19 | |Settings Meta Tags 20 | |![](Settings5.png?raw=true) 21 | 22 | |Deutsch 23 | | ------ 24 | |Hauptfenster 25 | |![](Cover.de.png?raw=true) 26 | |Hauptfenster, während der Konvertierung 27 | |![](Main-progr.de.png?raw=true) 28 | |Buchdetails (Metainformationen) 29 | |![](Details.de.png?raw=true) 30 | |Vorschau 31 | |![](Preview.de.png?raw=true) 32 | |Einstellungen Allgemein 33 | |![](Settings.de.png?raw=true) 34 | |Einstellungen Ordnerstruktur 35 | |![](Settings2.de.png?raw=true) 36 | |Einstellungen Konvertierung 37 | |![](Settings3.de.png?raw=true) 38 | |Einstellungen Kapitel 39 | |![](Settings4.de.png?raw=true) 40 | |Einstellungen Meta-Einträge 41 | |![](Settings5.de.png?raw=true) 42 | -------------------------------------------------------------------------------- /res/Settings.de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Settings.de.png -------------------------------------------------------------------------------- /res/Settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Settings.png -------------------------------------------------------------------------------- /res/Settings2.de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Settings2.de.png -------------------------------------------------------------------------------- /res/Settings2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Settings2.png -------------------------------------------------------------------------------- /res/Settings3.de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Settings3.de.png -------------------------------------------------------------------------------- /res/Settings3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Settings3.png -------------------------------------------------------------------------------- /res/Settings4.de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Settings4.de.png -------------------------------------------------------------------------------- /res/Settings4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Settings4.png -------------------------------------------------------------------------------- /res/Settings5.de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Settings5.de.png -------------------------------------------------------------------------------- /res/Settings5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/res/Settings5.png -------------------------------------------------------------------------------- /res/Setup.dat: -------------------------------------------------------------------------------- 1 | https://github.com/audiamus/AaxAudioConverter/releases/download/v1.18.2/AaxAudioConverter-1.18.2-Setup.exe 2 | MD5: caacf818b0c41f2280ea3d1c5982351b 3 | -------------------------------------------------------------------------------- /res/Setup.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Url": "https://github.com/audiamus/AaxAudioConverter/releases/download/v1.18.2/AaxAudioConverter-1.18.2-Setup.exe", 4 | "AppName": "AaxAudioConverter", 5 | "Version": "1.18.2", 6 | "Preview": false, 7 | "Descript": null, 8 | "Md5": "caacf818b0c41f2280ea3d1c5982351b" 9 | }, 10 | { 11 | "AppName": "BookLibConnect", 12 | "InfoLinkUrl": "https://raw.githubusercontent.com/audiamus/BookLibConnect/master/res/Setup.json" 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/AaxAudioConverter.de.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/src/AaxAudioConverter/AaxAudioConverter.de.odt -------------------------------------------------------------------------------- /src/AaxAudioConverter/AaxAudioConverter.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/src/AaxAudioConverter/AaxAudioConverter.odt -------------------------------------------------------------------------------- /src/AaxAudioConverter/AaxFileItemEx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using audiamus.aaxconv.lib; 4 | 5 | namespace audiamus.aaxconv { 6 | 7 | class AaxFileItemEx : IEquatable { 8 | public AaxFileItem FileItem {get; private set;} 9 | public ListViewItem ListViewItem {get; set;} 10 | 11 | public AaxFileItemEx (AaxFileItem fi) { 12 | if (fi is null) 13 | throw new ArgumentNullException (); 14 | FileItem = fi; 15 | } 16 | 17 | public bool Equals (AaxFileItemEx other) { 18 | //Check whether the compared objects reference the same data. 19 | if (Object.ReferenceEquals (this, other)) 20 | return true; 21 | 22 | //Check whether any of the compared objects is null. 23 | if (other is null || other.FileItem is null) 24 | return false; 25 | 26 | //Check whether the items' properties are equal. 27 | return this.FileItem.Equals (other.FileItem); 28 | } 29 | 30 | public override int GetHashCode () { 31 | //Check whether the object is null 32 | if (FileItem is null) 33 | return 0; 34 | 35 | return FileItem.GetHashCode (); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/AboutForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Windows.Forms; 4 | using static audiamus.aux.ApplEnv; 5 | 6 | namespace audiamus.aaxconv { 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 | 21 | private void linkLabelHomepage_LinkClicked (object sender, LinkLabelLinkClickedEventArgs e) { 22 | var s = ((LinkLabel)sender).Text; 23 | Process.Start (s); 24 | } 25 | } 26 | 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/ActivationCodeForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text.RegularExpressions; 6 | using System.Windows.Forms; 7 | using audiamus.aaxconv.lib.ex; 8 | using audiamus.aux.win; 9 | using static audiamus.aux.Logging; 10 | 11 | namespace audiamus.aaxconv { 12 | 13 | using R = Properties.Resources; 14 | 15 | partial class ActivationCodeForm : Form { 16 | readonly IAppSettings _settings = Properties.Settings.Default; 17 | readonly bool _suppressMsgBox; 18 | uint? _code; 19 | 20 | static readonly Regex _rgx = new Regex (@"^(([a-fA-F0-9]{2})\W?){3}([a-fA-F0-9]{2})$", RegexOptions.Compiled); 21 | 22 | private IAppSettings Settings => _settings; 23 | 24 | public ActivationCodeForm (bool suppressMsgBox = false) { 25 | InitializeComponent (); 26 | 27 | _suppressMsgBox = suppressMsgBox; 28 | 29 | textBox1.Text = Settings.ActivationCode.ToHexDashString (); 30 | 31 | } 32 | 33 | protected override void OnLoad (EventArgs e) { 34 | base.OnLoad (e); 35 | //if (!(Owner is null)) 36 | // this.Text = $"{Owner.Text} : {this.Text}"; 37 | } 38 | 39 | private void textBox1_TextChanged (object sender, EventArgs e) { 40 | bool succ = false; 41 | if (string.IsNullOrEmpty (textBox1.Text) && Settings.ActivationCode.HasValue) { 42 | _code = null; 43 | succ = true; 44 | } else { 45 | //group 2, 4 captures 46 | var match = _rgx.Match (textBox1.Text); 47 | 48 | succ = match.Success; 49 | if (succ && match.Groups.Count == 4) { 50 | var caps = match.Groups[2].Captures; 51 | var chars = caps.Cast ().Select (c => c.Value).ToList (); 52 | chars.Add (match.Groups[3].Value); 53 | _code = chars.ToUInt32 (); 54 | } 55 | } 56 | btnOk.Enabled = succ; 57 | AcceptButton = btnOk.Enabled ? btnOk : btnCancel; 58 | } 59 | 60 | private void btnOk_Click (object sender, EventArgs e) { 61 | string msg; 62 | if (_code.HasValue) { 63 | msg = R.MsgNoteActivationCode; 64 | Log (2, this, "custom code set"); 65 | } else { 66 | msg = R.MsgActivationCodeRemoved; 67 | Log (2, this, "custom code removed"); 68 | } 69 | 70 | if (Settings.ActivationCode != _code && !_suppressMsgBox) 71 | MsgBox.Show (this, msg, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information); 72 | 73 | Settings.ActivationCode = _code; 74 | 75 | DialogResult = DialogResult.OK; 76 | Close (); 77 | } 78 | 79 | private void btnDummy_Click (object sender, EventArgs e) { 80 | textBox1.Text = "00-00-00-00"; 81 | } 82 | 83 | private void linkLblBLC_LinkClicked (object sender, LinkLabelLinkClickedEventArgs e) { 84 | string link = "https://github.com/audiamus/BookLibConnect"; 85 | Process.Start (link); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/FFmpegLocationForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace audiamus.aaxconv { 2 | partial class FFmpegLocationForm { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose (bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose (); 15 | } 16 | base.Dispose (disposing); 17 | } 18 | 19 | #region Windows Form Designer generated code 20 | 21 | /// 22 | /// Required method for Designer support - do not modify 23 | /// the contents of this method with the code editor. 24 | /// 25 | private void InitializeComponent () { 26 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FFmpegLocationForm)); 27 | this.textBoxLocation = new System.Windows.Forms.TextBox(); 28 | this.btnLocate = new System.Windows.Forms.Button(); 29 | this.labelCaption = new System.Windows.Forms.Label(); 30 | this.btnOK = new System.Windows.Forms.Button(); 31 | this.btnCancel = new System.Windows.Forms.Button(); 32 | this.btnReset = new System.Windows.Forms.Button(); 33 | this.SuspendLayout(); 34 | // 35 | // textBoxLocation 36 | // 37 | resources.ApplyResources(this.textBoxLocation, "textBoxLocation"); 38 | this.textBoxLocation.Name = "textBoxLocation"; 39 | this.textBoxLocation.ReadOnly = true; 40 | // 41 | // btnLocate 42 | // 43 | resources.ApplyResources(this.btnLocate, "btnLocate"); 44 | this.btnLocate.Name = "btnLocate"; 45 | this.btnLocate.UseVisualStyleBackColor = true; 46 | this.btnLocate.Click += new System.EventHandler(this.btnLocate_Click); 47 | // 48 | // labelCaption 49 | // 50 | resources.ApplyResources(this.labelCaption, "labelCaption"); 51 | this.labelCaption.Name = "labelCaption"; 52 | // 53 | // btnOK 54 | // 55 | resources.ApplyResources(this.btnOK, "btnOK"); 56 | this.btnOK.Name = "btnOK"; 57 | this.btnOK.UseVisualStyleBackColor = true; 58 | this.btnOK.Click += new System.EventHandler(this.btnOK_Click); 59 | // 60 | // btnCancel 61 | // 62 | resources.ApplyResources(this.btnCancel, "btnCancel"); 63 | this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; 64 | this.btnCancel.Name = "btnCancel"; 65 | this.btnCancel.UseVisualStyleBackColor = true; 66 | // 67 | // btnReset 68 | // 69 | resources.ApplyResources(this.btnReset, "btnReset"); 70 | this.btnReset.Name = "btnReset"; 71 | this.btnReset.UseVisualStyleBackColor = true; 72 | this.btnReset.Click += new System.EventHandler(this.btnReset_Click); 73 | // 74 | // FFmpegLocationForm 75 | // 76 | this.AcceptButton = this.btnLocate; 77 | resources.ApplyResources(this, "$this"); 78 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 79 | this.CancelButton = this.btnCancel; 80 | this.Controls.Add(this.btnReset); 81 | this.Controls.Add(this.btnCancel); 82 | this.Controls.Add(this.btnOK); 83 | this.Controls.Add(this.labelCaption); 84 | this.Controls.Add(this.btnLocate); 85 | this.Controls.Add(this.textBoxLocation); 86 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 87 | this.MaximizeBox = false; 88 | this.MinimizeBox = false; 89 | this.Name = "FFmpegLocationForm"; 90 | this.ResumeLayout(false); 91 | this.PerformLayout(); 92 | 93 | } 94 | 95 | #endregion 96 | 97 | private System.Windows.Forms.TextBox textBoxLocation; 98 | private System.Windows.Forms.Button btnLocate; 99 | private System.Windows.Forms.Label labelCaption; 100 | private System.Windows.Forms.Button btnOK; 101 | private System.Windows.Forms.Button btnCancel; 102 | private System.Windows.Forms.Button btnReset; 103 | } 104 | } -------------------------------------------------------------------------------- /src/AaxAudioConverter/FFmpegLocationForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Windows.Forms; 4 | using audiamus.aaxconv.lib; 5 | using audiamus.aux; 6 | using audiamus.aux.win; 7 | 8 | namespace audiamus.aaxconv { 9 | using System.ComponentModel; 10 | using R = Properties.Resources; 11 | 12 | partial class FFmpegLocationForm : Form { 13 | readonly IAppSettings _settings = Properties.Settings.Default; 14 | readonly string _origFFMpegDirectory; 15 | 16 | readonly AaxAudioConverter _converter; 17 | readonly Func _callback; 18 | 19 | private IAppSettings Settings => _settings; 20 | 21 | 22 | public FFmpegLocationForm (AaxAudioConverter converter, Func callback) { 23 | InitializeComponent (); 24 | _converter = converter; 25 | _callback = callback; 26 | _origFFMpegDirectory = Settings.FFMpegDirectory; 27 | textBoxLocation.Text = _origFFMpegDirectory; 28 | } 29 | 30 | protected override void OnClosing (CancelEventArgs e) { 31 | if (DialogResult == DialogResult.Cancel) 32 | Settings.FFMpegDirectory = _origFFMpegDirectory; 33 | } 34 | 35 | private void btnLocate_Click (object sender, EventArgs e) { 36 | 37 | OpenFileDialog ofd = new OpenFileDialog { 38 | InitialDirectory = Settings.FFMpegDirectory, 39 | CheckFileExists = true, 40 | CheckPathExists = true, 41 | FileName = FFmpeg.FFMPEG_EXE, 42 | Filter = R.FilterExeFiles // "Executable files (*.exe)|*.exe" 43 | }; 44 | DialogResult result = ofd.ShowDialog (); 45 | if (result == DialogResult.Cancel) 46 | return; 47 | 48 | string ffmpegdir = Path.GetDirectoryName (ofd.FileName); 49 | textBoxLocation.Text = ffmpegdir; 50 | string path = Path.Combine (ffmpegdir, FFmpeg.FFMPEG_EXE); 51 | if (File.Exists (path)) 52 | Settings.FFMpegDirectory = ffmpegdir; 53 | 54 | bool succ = _converter.VerifyFFmpegPathVersion(_callback); 55 | 56 | if (succ) 57 | enableOK (); 58 | } 59 | 60 | private void btnReset_Click (object sender, EventArgs e) { 61 | string ffmpegdir = ApplEnv.ApplDirectory; 62 | string path = Path.Combine (ffmpegdir, FFmpeg.FFMPEG_EXE); 63 | if (File.Exists (path)) { 64 | Settings.FFMpegDirectory = ffmpegdir; 65 | using (new ResourceGuard (() => Settings.FFMpegDirectory = _origFFMpegDirectory)) { 66 | bool succ = _converter.VerifyFFmpegPathVersion (_callback); 67 | if (succ) { 68 | textBoxLocation.Text = null; 69 | enableOK (); 70 | } 71 | } 72 | } 73 | } 74 | 75 | private void btnOK_Click (object sender, EventArgs e) { 76 | Settings.FFMpegDirectory = string.IsNullOrWhiteSpace(textBoxLocation.Text) ? null : textBoxLocation.Text; 77 | 78 | if (string.Equals (Settings.FFMpegDirectory, ApplEnv.ApplDirectory, StringComparison.InvariantCultureIgnoreCase)) 79 | Settings.FFMpegDirectory = null; 80 | 81 | DialogResult = DialogResult.OK; 82 | } 83 | 84 | private void enableOK () { 85 | //"Location and verification successful" 86 | MsgBox.Show (this, R.MsgLocationVerifSucc, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information); 87 | btnOK.Enabled = true; 88 | this.AcceptButton = btnOK; 89 | this.ActiveControl = btnOK; 90 | } 91 | 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/FileAssoc.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Reflection; 3 | using System.Threading.Tasks; 4 | using System.Windows.Forms; 5 | using audiamus.aux.w32; 6 | using audiamus.aux.win; 7 | using static audiamus.aux.ApplEnv; 8 | using static audiamus.aux.Logging; 9 | 10 | namespace audiamus.aaxconv { 11 | 12 | using R = Properties.Resources; 13 | 14 | class FileAssoc { 15 | readonly IAppSettings _settings; 16 | readonly IEnumerable _extensions = new[] { ".aax", ".aa" }; 17 | readonly string _fileDesc; 18 | readonly Assembly _assembly; 19 | readonly Control _owner; 20 | 21 | private IAppSettings Settings => _settings; 22 | 23 | public FileAssoc (IAppSettings settings, Control owner) { 24 | _settings = settings; 25 | _assembly = EntryAssembly; 26 | _owner = owner; 27 | 28 | var control = _owner; 29 | while (!(control.Parent is null)) 30 | control = control.Parent; 31 | _fileDesc = control.Text; 32 | } 33 | 34 | public void AssociateInit () { 35 | if (Settings.FileAssoc.HasValue && !Settings.FileAssoc.Value) 36 | return; 37 | 38 | if (!Settings.FileAssoc.HasValue) { 39 | 40 | string msg = $"{R.MsgFileAssoc} {ApplName}?"; 41 | var result = MsgBox.Show (_owner, msg, _fileDesc, MessageBoxButtons.YesNo, MessageBoxIcon.Question); 42 | 43 | Settings.FileAssoc = result == DialogResult.Yes; 44 | if (result != DialogResult.Yes) 45 | return; 46 | } 47 | 48 | Task.Run (() => Associate ()); 49 | } 50 | 51 | public void Update () { 52 | Task.Run (() => 53 | { 54 | if (Settings.FileAssoc ?? false) 55 | Associate (); 56 | else 57 | Remove (); 58 | }); 59 | } 60 | 61 | public void Associate () { 62 | Log0 (3, this); 63 | FileAssociations.EnsureAssociationsSet (_extensions, _fileDesc, _assembly); 64 | } 65 | 66 | public void Remove () { 67 | Log0 (3, this); 68 | FileAssociations.RemoveAssociationsSet (_extensions, _assembly); 69 | } 70 | } 71 | } 72 | 73 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/FileDetailsForm.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Windows.Forms; 3 | using audiamus.aaxconv.ex; 4 | using audiamus.aaxconv.lib; 5 | using audiamus.aux.ex; 6 | using audiamus.aux.win; 7 | 8 | namespace audiamus.aaxconv { 9 | using R = Properties.Resources; 10 | 11 | partial class FileDetailsForm : FileItemForm { 12 | 13 | public FileDetailsForm () { 14 | InitializeComponent (); 15 | } 16 | 17 | 18 | public override void Set (AaxFileItem fileItem) { 19 | textBoxTitle.Text = fileItem.BookTitle; 20 | 21 | var rtfbld = new RtfBuilder (); 22 | 23 | rtfbld.AppendItem (R.HdrAuthor, fileItem.Author); 24 | rtfbld.AppendItem (R.HdrNarrator, fileItem.Narrator); 25 | rtfbld.AppendItem (R.HdrSize, $"{fileItem.FileSize / (1024 * 1024)} MB"); 26 | rtfbld.AppendItem (R.HdrDuration, fileItem.Duration.ToStringHMS ()); 27 | rtfbld.AppendItem (R.HdrYear, fileItem.PublishingDate?.Year.ToString ()); 28 | rtfbld.AppendItem (R.HdrPublisher, fileItem.Publisher); 29 | rtfbld.AppendItem (R.HdrCopyright, fileItem.Copyright); 30 | 31 | 32 | string rtf = rtfbld.ToRtf (); 33 | richTextBoxMeta.Clear (); 34 | richTextBoxMeta.Rtf = rtf; 35 | 36 | var converter = new ImageConverter (); 37 | try { 38 | pictureBox.Image = converter.ConvertFrom (fileItem.Cover) as Image; 39 | } catch { } 40 | 41 | richTextBoxAbstract.Clear (); 42 | richTextBoxAbstract.Text = fileItem.Abstract; 43 | } 44 | 45 | protected override void OnKeyDown (KeyEventArgs e) { 46 | if (e.KeyCode == Keys.Escape) 47 | Close (); 48 | else 49 | base.OnKeyDown (e); 50 | } 51 | 52 | } 53 | 54 | namespace ex { 55 | static class RtfBuilderEx { 56 | public static void AppendItem (this RtfBuilder rtfbld, string header, string body) { 57 | rtfbld.AppendBold (header); 58 | rtfbld.AppendLine (); 59 | rtfbld.Append (body); 60 | //rtfbld.AppendLine (); 61 | rtfbld.AppendPara (); 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/FileItemForm.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Windows.Forms; 3 | using audiamus.aaxconv.lib; 4 | 5 | namespace audiamus.aaxconv { 6 | interface ISet { 7 | void Set (AaxFileItem fileItem); 8 | } 9 | 10 | class FileItemForm : Form, ISet { 11 | [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 12 | [Browsable (false)] 13 | public IPreviewTitle Previewer { get; set; } 14 | public virtual void Set (AaxFileItem fileItem) { } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/GenresForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace audiamus.aaxconv { 2 | partial class GenresForm { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose (bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose (); 15 | } 16 | base.Dispose (disposing); 17 | } 18 | 19 | #region Windows Form Designer generated code 20 | 21 | /// 22 | /// Required method for Designer support - do not modify 23 | /// the contents of this method with the code editor. 24 | /// 25 | private void InitializeComponent () { 26 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GenresForm)); 27 | this.panel1 = new System.Windows.Forms.Panel(); 28 | this.btnCancel = new System.Windows.Forms.Button(); 29 | this.btnOK = new System.Windows.Forms.Button(); 30 | this.listBox = new System.Windows.Forms.ListBox(); 31 | this.panel1.SuspendLayout(); 32 | this.SuspendLayout(); 33 | // 34 | // panel1 35 | // 36 | resources.ApplyResources(this.panel1, "panel1"); 37 | this.panel1.Controls.Add(this.btnCancel); 38 | this.panel1.Controls.Add(this.btnOK); 39 | this.panel1.Name = "panel1"; 40 | // 41 | // btnCancel 42 | // 43 | resources.ApplyResources(this.btnCancel, "btnCancel"); 44 | this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; 45 | this.btnCancel.Name = "btnCancel"; 46 | this.btnCancel.UseVisualStyleBackColor = true; 47 | // 48 | // btnOK 49 | // 50 | resources.ApplyResources(this.btnOK, "btnOK"); 51 | this.btnOK.Name = "btnOK"; 52 | this.btnOK.UseVisualStyleBackColor = true; 53 | this.btnOK.Click += new System.EventHandler(this.btnOK_Click); 54 | // 55 | // listBox 56 | // 57 | resources.ApplyResources(this.listBox, "listBox"); 58 | this.listBox.FormattingEnabled = true; 59 | this.listBox.Name = "listBox"; 60 | this.listBox.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended; 61 | this.listBox.SelectedIndexChanged += new System.EventHandler(this.listBox_SelectedIndexChanged); 62 | // 63 | // GenresForm 64 | // 65 | this.AcceptButton = this.btnCancel; 66 | resources.ApplyResources(this, "$this"); 67 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 68 | this.CancelButton = this.btnCancel; 69 | this.ControlBox = false; 70 | this.Controls.Add(this.listBox); 71 | this.Controls.Add(this.panel1); 72 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 73 | this.Name = "GenresForm"; 74 | this.panel1.ResumeLayout(false); 75 | this.ResumeLayout(false); 76 | 77 | } 78 | 79 | #endregion 80 | 81 | private System.Windows.Forms.Panel panel1; 82 | private System.Windows.Forms.Button btnCancel; 83 | private System.Windows.Forms.Button btnOK; 84 | private System.Windows.Forms.ListBox listBox; 85 | } 86 | } -------------------------------------------------------------------------------- /src/AaxAudioConverter/GenresForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Windows.Forms; 4 | using audiamus.aux.ex; 5 | using audiamus.aux.win; 6 | 7 | namespace audiamus.aaxconv { 8 | using R = Properties.Resources; 9 | 10 | partial class GenresForm : Form { 11 | private readonly lib.IConvSettings _settings; 12 | 13 | private lib.IConvSettings Settings => _settings; 14 | 15 | public GenresForm (lib.IConvSettings settings) { 16 | InitializeComponent (); 17 | _settings = settings; 18 | 19 | var names = Settings.Genres.SplitTrim (';'); 20 | listBox.Items.AddRange (names); 21 | } 22 | 23 | private void listBox_SelectedIndexChanged (object sender, EventArgs e) => 24 | btnOK.Enabled = listBox.SelectedIndices.Count > 0; 25 | 26 | private void btnOK_Click (object sender, EventArgs e) { 27 | if (listBox.SelectedIndices.Count > 0) { 28 | var result = MsgBox.Show (this, R.MsgRemoveGenres, Owner.Text, MessageBoxButtons.YesNo, 29 | MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); 30 | 31 | if (result == DialogResult.Yes) { 32 | var names = Settings.Genres.SplitTrim (';').ToList (); 33 | foreach (int idx in listBox.SelectedIndices) { 34 | string name = (string)listBox.Items[idx]; 35 | names.Remove (name); 36 | } 37 | Settings.Genres = names.Combine (); 38 | } 39 | } 40 | Close (); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/PerformanceHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | using audiamus.perf; 8 | 9 | namespace audiamus.aaxconv { 10 | class PerformanceHandler { 11 | private readonly ProgressBar _pbProcesses; 12 | private readonly ProgressBar _pbLoadPercent; 13 | private readonly ToolTip _tt; 14 | private readonly string _tttProcesses; 15 | private readonly string _tttLoad; 16 | 17 | public PerformanceHandler (ProgressBar pbProcesses, ProgressBar pbLoadPercent, ToolTip tt = null) { 18 | _pbProcesses = pbProcesses; 19 | _pbLoadPercent = pbLoadPercent; 20 | 21 | _tt = tt; 22 | _tttProcesses = tt?.GetToolTip (pbProcesses); 23 | _tttLoad = tt?.GetToolTip (pbLoadPercent); 24 | } 25 | 26 | public void Reset () { 27 | _pbProcesses.Value = 0; 28 | _pbLoadPercent.Value = 0; 29 | _tt.SetToolTip (_pbProcesses, _tttProcesses); 30 | _tt.SetToolTip (_pbLoadPercent, _tttLoad); 31 | } 32 | 33 | public void Update (IPerfCallback callback) { 34 | update (callback.Processes, _pbProcesses, _tttProcesses); 35 | update (callback.LoadPercent, _pbLoadPercent, _tttLoad, "%"); 36 | } 37 | 38 | private void update (IValueMax vm, ProgressBar pb, string ttt, string suffix = null) { 39 | if (vm is null) 40 | return; 41 | 42 | if (vm.Max != pb.Maximum) 43 | pb.Maximum = vm.Max; 44 | 45 | int val = Math.Min (vm.Value, pb.Maximum); 46 | pb.Value = val; 47 | if (_tt is null || ttt is null) 48 | return; 49 | 50 | var caption = $"{ttt} : {val}{suffix}"; 51 | _tt.SetToolTip (pb, caption); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Threading; 4 | using System.Windows.Forms; 5 | using audiamus.aux; 6 | using audiamus.aux.win; 7 | 8 | namespace audiamus.aaxconv { 9 | static class Program { 10 | 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main (string[] args) { 16 | using (Mutex mutex = new Mutex (false, ApplEnv.AssemblyGuid)) { 17 | 18 | if (!mutex.WaitOne (0, false)) 19 | return; 20 | 21 | var ap = new ArgParser (args); 22 | uint? loglevel = ap.FindUIntArg ("Log"); 23 | if (loglevel.HasValue) { 24 | Logging.InstantFlush = true; 25 | Logging.Level = (int)loglevel; 26 | } 27 | 28 | Application.EnableVisualStyles (); 29 | Application.SetCompatibleTextRenderingDefault (false); 30 | 31 | CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; 32 | Culture.Init (Properties.Settings.Default); 33 | 34 | Application.Run (new MainForm ()); 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle ("AAX Audio Converter")] 10 | [assembly: AssemblyDescription ("")] 11 | [assembly: AssemblyConfiguration ("")] 12 | [assembly: AssemblyCompany ("audiamus")] 13 | [assembly: AssemblyProduct ("AaxAudioConverter")] 14 | [assembly: AssemblyCopyright ("Copyright © 2019 - 2023 audiamus")] 15 | [assembly: AssemblyTrademark ("")] 16 | [assembly: AssemblyCulture ("")] 17 | 18 | // Setting ComVisible to false makes the types in this assembly not visible 19 | // to COM components. If you need to access a type in this assembly from 20 | // COM, set the ComVisible attribute to true on that type. 21 | [assembly: ComVisible (false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | [assembly: Guid ("d186de5d-0dec-4fe8-80bc-9f473e804604")] 25 | 26 | // Version information for an assembly consists of the following four values: 27 | // 28 | // Major Version 29 | // Minor Version 30 | // Build Number 31 | // Revision 32 | // 33 | // You can specify all the values or you can default the Build and Revision Numbers 34 | // by using the '*' as shown below: 35 | // [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyVersion ("1.18.2.0")] 37 | [assembly: AssemblyFileVersion ("1.18.2.0")] 38 | [assembly: NeutralResourcesLanguage ("en")] 39 | 40 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/Resources.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using audiamus.aaxconv.lib; 3 | using audiamus.aux.ex; 4 | 5 | namespace audiamus.aaxconv { 6 | 7 | using R = Properties.Resources; 8 | 9 | class Resources : IResources { 10 | private static Resources __resources; 11 | private ResourceManager ResourceManager { get; } 12 | 13 | public static Resources Default { 14 | get 15 | { 16 | if (__resources is null) { 17 | __resources = new Resources (); 18 | } 19 | return __resources; 20 | } 21 | } 22 | 23 | private Resources () => ResourceManager = this.GetDefaultResourceManager (); 24 | 25 | public string MsgFFmpegVersion1 => R.MsgFFmpegVersion1; 26 | public string MsgFFmpegVersion2 => R.MsgFFmpegVersion2; 27 | public string MsgFFmpegVersion3 => R.MsgFFmpegVersion3; 28 | public string MsgFFmpegVersion4 => R.MsgFFmpegVersion4; 29 | public string MsgActivationError1 => R.MsgActivationError1; 30 | public string MsgActivationError2 => R.MsgActivationError2; 31 | public string MsgActivationError3 => R.MsgActivationError3; 32 | public string MsgInvalidInternalFileType => R.MsgInvalidInternalFileType; 33 | public string MsgDirectoryCreationCallback => R.MsgDirectoryCreationCallback; 34 | public string MsgDirectoryPartCreationCallback => R.MsgDirectoryPartCreationCallback; 35 | public string MsgDirectoryCreationCallbackForAll => R.MsgDirectoryCreationCallbackForAll; 36 | public string PartNames => R.PartNames; 37 | //public string MsgOnlineUpdateNewVersion => R.MsgOnlineUpdateNewVersion; 38 | //public string MsgOnlineUpdateDownload => R.MsgOnlineUpdateDownload; 39 | //public string MsgOnlineUpdateInstall => R.MsgOnlineUpdateInstall; 40 | //public string MsgOnlineUpdateInstallNow => R.MsgOnlineUpdateInstallNow; 41 | //public string MsgOnlineUpdateInstallLater => R.MsgOnlineUpdateInstallLater; 42 | 43 | public string HdrAuthor => R.HdrAuthor; 44 | public string HdrTitle => R.HdrTitle; 45 | public string HdrNarrator => R.HdrNarrator; 46 | public string HdrDuration => R.HdrDuration; 47 | public string HdrYear => R.HdrYear; 48 | public string HdrPublisher => R.HdrPublisher; 49 | public string HdrCopyright => R.HdrCopyright; 50 | public string HdrGenre => R.HdrGenre; 51 | public string HdrSampleRate => R.HdrSampleRate; 52 | public string HdrBitRate => R.HdrBitRate; 53 | 54 | public string PartNamePrefixStandard => ResourceManager.GetStringEx ("Part"); 55 | public string ChapterNamePrefixStandard => ResourceManager.GetStringEx ("Chapter"); 56 | 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/Resources/added.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/src/AaxAudioConverter/Resources/added.png -------------------------------------------------------------------------------- /src/AaxAudioConverter/Resources/audio.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/src/AaxAudioConverter/Resources/audio.ico -------------------------------------------------------------------------------- /src/AaxAudioConverter/Resources/audio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/src/AaxAudioConverter/Resources/audio.png -------------------------------------------------------------------------------- /src/AaxAudioConverter/Resources/blank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/src/AaxAudioConverter/Resources/blank.png -------------------------------------------------------------------------------- /src/AaxAudioConverter/Resources/hidden features de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/src/AaxAudioConverter/Resources/hidden features de.png -------------------------------------------------------------------------------- /src/AaxAudioConverter/Resources/hidden features en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/src/AaxAudioConverter/Resources/hidden features en.png -------------------------------------------------------------------------------- /src/AaxAudioConverter/Settings.cs: -------------------------------------------------------------------------------- 1 | using audiamus.aaxconv.lib; 2 | 3 | namespace audiamus.aaxconv { 4 | 5 | interface IAppSettings : lib.IConvSettings, aux.win.ILanguageSetting { 6 | bool? FileAssoc { get; set; } 7 | bool? ShowStartupTip { get; set; } 8 | bool FileDateColumn { get; set; } 9 | int SettingsTab { get; set; } 10 | 11 | void Save (); 12 | void FixNarrator (); 13 | } 14 | 15 | interface IAppSettingsOnlineUpdateEx { 16 | string OnlineUpdateUrl { get; } 17 | bool OnlineUpdateDebug { get; } 18 | } 19 | 20 | namespace Properties { 21 | [System.Configuration.SettingsProvider (typeof (aux.LocalFileSettingsProvider))] 22 | partial class Settings : IAppSettings, IAppSettingsOnlineUpdateEx { 23 | 24 | public bool ConvertByFileDate { get; set; } 25 | 26 | public void FixNarrator () { 27 | TagArtist = fixNarrator (TagArtist); 28 | TagAlbumArtist = fixNarrator (TagAlbumArtist); 29 | TagComposer = fixNarrator (TagComposer); 30 | TagConductor = fixNarrator (TagConductor); 31 | Narrator = null; 32 | } 33 | 34 | private ERoleTagAssignment fixNarrator (ERoleTagAssignment role) { 35 | bool narrator = Narrator ?? false; 36 | switch (role) { 37 | default: 38 | return role; 39 | case ERoleTagAssignment.author__narrator__: 40 | if (narrator) 41 | return ERoleTagAssignment.author_narrator; 42 | else 43 | return ERoleTagAssignment.author; 44 | case ERoleTagAssignment.__narrator__: 45 | if (narrator) 46 | return ERoleTagAssignment.narrator; 47 | else 48 | return ERoleTagAssignment.none; 49 | } 50 | 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/StartupTipForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace audiamus.aaxconv { 2 | partial class StartupTipForm { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose (bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose (); 15 | } 16 | base.Dispose (disposing); 17 | } 18 | 19 | #region Windows Form Designer generated code 20 | 21 | /// 22 | /// Required method for Designer support - do not modify 23 | /// the contents of this method with the code editor. 24 | /// 25 | private void InitializeComponent () { 26 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(StartupTipForm)); 27 | this.panel1 = new System.Windows.Forms.Panel(); 28 | this.label2 = new System.Windows.Forms.Label(); 29 | this.ckBoxDisable = new System.Windows.Forms.CheckBox(); 30 | this.btnOK = new System.Windows.Forms.Button(); 31 | this.pictureBox1 = new System.Windows.Forms.PictureBox(); 32 | this.panel2 = new System.Windows.Forms.Panel(); 33 | this.label1 = new System.Windows.Forms.Label(); 34 | this.panel1.SuspendLayout(); 35 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); 36 | this.panel2.SuspendLayout(); 37 | this.SuspendLayout(); 38 | // 39 | // panel1 40 | // 41 | resources.ApplyResources(this.panel1, "panel1"); 42 | this.panel1.Controls.Add(this.label2); 43 | this.panel1.Controls.Add(this.ckBoxDisable); 44 | this.panel1.Controls.Add(this.btnOK); 45 | this.panel1.Name = "panel1"; 46 | // 47 | // label2 48 | // 49 | resources.ApplyResources(this.label2, "label2"); 50 | this.label2.Name = "label2"; 51 | // 52 | // ckBoxDisable 53 | // 54 | resources.ApplyResources(this.ckBoxDisable, "ckBoxDisable"); 55 | this.ckBoxDisable.Name = "ckBoxDisable"; 56 | this.ckBoxDisable.UseVisualStyleBackColor = true; 57 | // 58 | // btnOK 59 | // 60 | resources.ApplyResources(this.btnOK, "btnOK"); 61 | this.btnOK.DialogResult = System.Windows.Forms.DialogResult.Cancel; 62 | this.btnOK.Name = "btnOK"; 63 | this.btnOK.UseVisualStyleBackColor = true; 64 | this.btnOK.Click += new System.EventHandler(this.btnOK_Click); 65 | // 66 | // pictureBox1 67 | // 68 | resources.ApplyResources(this.pictureBox1, "pictureBox1"); 69 | this.pictureBox1.Name = "pictureBox1"; 70 | this.pictureBox1.TabStop = false; 71 | // 72 | // panel2 73 | // 74 | resources.ApplyResources(this.panel2, "panel2"); 75 | this.panel2.Controls.Add(this.label1); 76 | this.panel2.Name = "panel2"; 77 | // 78 | // label1 79 | // 80 | resources.ApplyResources(this.label1, "label1"); 81 | this.label1.Name = "label1"; 82 | // 83 | // StartupTipForm 84 | // 85 | this.AcceptButton = this.btnOK; 86 | resources.ApplyResources(this, "$this"); 87 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 88 | this.CancelButton = this.btnOK; 89 | this.Controls.Add(this.pictureBox1); 90 | this.Controls.Add(this.panel2); 91 | this.Controls.Add(this.panel1); 92 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 93 | this.MaximizeBox = false; 94 | this.Name = "StartupTipForm"; 95 | this.panel1.ResumeLayout(false); 96 | this.panel1.PerformLayout(); 97 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); 98 | this.panel2.ResumeLayout(false); 99 | this.panel2.PerformLayout(); 100 | this.ResumeLayout(false); 101 | 102 | } 103 | 104 | #endregion 105 | 106 | private System.Windows.Forms.Panel panel1; 107 | private System.Windows.Forms.Button btnOK; 108 | private System.Windows.Forms.CheckBox ckBoxDisable; 109 | private System.Windows.Forms.PictureBox pictureBox1; 110 | private System.Windows.Forms.Panel panel2; 111 | private System.Windows.Forms.Label label1; 112 | private System.Windows.Forms.Label label2; 113 | } 114 | } -------------------------------------------------------------------------------- /src/AaxAudioConverter/StartupTipForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | 6 | namespace audiamus.aaxconv { 7 | partial class StartupTipForm : Form { 8 | private readonly IAppSettings _settings; 9 | 10 | public StartupTipForm (IAppSettings settings) { 11 | InitializeComponent (); 12 | _settings = settings; 13 | if (_settings.ShowStartupTip.HasValue) 14 | ckBoxDisable.Checked = !_settings.ShowStartupTip.Value; 15 | 16 | } 17 | 18 | 19 | protected override void OnLoad (EventArgs e) { 20 | Location = new Point (Owner.Location.X + (Owner.Width - Width) / 2, Owner.Location.Y + (Owner.Height - Height) / 2); 21 | base.OnLoad (e); 22 | } 23 | 24 | protected override void OnClosing (CancelEventArgs e) { 25 | base.OnClosing (e); 26 | _settings.ShowStartupTip = !ckBoxDisable.Checked; 27 | } 28 | 29 | private void btnOK_Click (object sender, EventArgs e) => Close (); 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/TypeConvertersRM.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using audiamus.aux; 3 | using audiamus.aux.ex; 4 | 5 | namespace audiamus.aaxconv { 6 | class BooleanYesNoConverterRM : BooleanYesNoConverter { 7 | public BooleanYesNoConverterRM () { 8 | ResourceManager = this.GetDefaultResourceManager(); 9 | } 10 | } 11 | 12 | class EnumChainConverterRM : EnumChainConverter 13 | where TEnum : struct, Enum 14 | where TPunct : class, IChainPunctuation, new() 15 | { 16 | public EnumChainConverterRM () { 17 | ResourceManager = this.GetDefaultResourceManager(); 18 | } 19 | } 20 | 21 | class EnumConverterRM : EnumConverter 22 | where TEnum : struct, Enum 23 | { 24 | public EnumConverterRM () { 25 | ResourceManager = this.GetDefaultResourceManager(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/WhatsNewForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace audiamus.aaxconv { 2 | partial class WhatsNewForm { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose (bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose (); 15 | } 16 | base.Dispose (disposing); 17 | } 18 | 19 | #region Windows Form Designer generated code 20 | 21 | /// 22 | /// Required method for Designer support - do not modify 23 | /// the contents of this method with the code editor. 24 | /// 25 | private void InitializeComponent () { 26 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(WhatsNewForm)); 27 | this.panel1 = new System.Windows.Forms.Panel(); 28 | this.btnOK = new System.Windows.Forms.Button(); 29 | this.lblPrev = new System.Windows.Forms.Label(); 30 | this.richTextBox1 = new System.Windows.Forms.RichTextBox(); 31 | this.panel2 = new System.Windows.Forms.Panel(); 32 | this.panel1.SuspendLayout(); 33 | this.panel2.SuspendLayout(); 34 | this.SuspendLayout(); 35 | // 36 | // panel1 37 | // 38 | this.panel1.Controls.Add(this.btnOK); 39 | this.panel1.Controls.Add(this.lblPrev); 40 | resources.ApplyResources(this.panel1, "panel1"); 41 | this.panel1.Name = "panel1"; 42 | // 43 | // btnOK 44 | // 45 | resources.ApplyResources(this.btnOK, "btnOK"); 46 | this.btnOK.DialogResult = System.Windows.Forms.DialogResult.Cancel; 47 | this.btnOK.Name = "btnOK"; 48 | this.btnOK.UseVisualStyleBackColor = true; 49 | // 50 | // lblPrev 51 | // 52 | resources.ApplyResources(this.lblPrev, "lblPrev"); 53 | this.lblPrev.Name = "lblPrev"; 54 | // 55 | // richTextBox1 56 | // 57 | this.richTextBox1.BackColor = System.Drawing.SystemColors.Window; 58 | this.richTextBox1.BorderStyle = System.Windows.Forms.BorderStyle.None; 59 | resources.ApplyResources(this.richTextBox1, "richTextBox1"); 60 | this.richTextBox1.Name = "richTextBox1"; 61 | this.richTextBox1.ReadOnly = true; 62 | // 63 | // panel2 64 | // 65 | this.panel2.BackColor = System.Drawing.SystemColors.Window; 66 | this.panel2.Controls.Add(this.richTextBox1); 67 | resources.ApplyResources(this.panel2, "panel2"); 68 | this.panel2.Name = "panel2"; 69 | // 70 | // WhatsNewForm 71 | // 72 | this.AcceptButton = this.btnOK; 73 | resources.ApplyResources(this, "$this"); 74 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 75 | this.CancelButton = this.btnOK; 76 | this.ControlBox = false; 77 | this.Controls.Add(this.panel2); 78 | this.Controls.Add(this.panel1); 79 | this.MaximizeBox = false; 80 | this.MinimizeBox = false; 81 | this.Name = "WhatsNewForm"; 82 | this.panel1.ResumeLayout(false); 83 | this.panel1.PerformLayout(); 84 | this.panel2.ResumeLayout(false); 85 | this.ResumeLayout(false); 86 | 87 | } 88 | 89 | #endregion 90 | 91 | private System.Windows.Forms.Panel panel1; 92 | private System.Windows.Forms.Button btnOK; 93 | private System.Windows.Forms.Label lblPrev; 94 | private System.Windows.Forms.RichTextBox richTextBox1; 95 | private System.Windows.Forms.Panel panel2; 96 | } 97 | } -------------------------------------------------------------------------------- /src/AaxAudioConverter/WhatsNewForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using audiamus.aux; 4 | 5 | namespace audiamus.aaxconv { 6 | partial class WhatsNewForm : Form { 7 | 8 | public WhatsNewForm () { 9 | InitializeComponent (); 10 | } 11 | 12 | 13 | protected override void OnLoad (EventArgs e) { 14 | base.OnLoad (e); 15 | 16 | try { 17 | var version = ApplEnv.AssemblyVersion; 18 | int fields = 2; 19 | if (version.Revision > 0) 20 | fields = 4; 21 | else if (version.Build > 0) 22 | fields = 3; 23 | 24 | Text = $"{Owner.Text}, Version {version.ToString (fields)} : {Text}"; 25 | 26 | richTextBox1.Rtf = Properties.Resources.LatestRtf; 27 | } catch (Exception) { 28 | } 29 | } 30 | 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 52 | 59 | 60 | 61 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /src/AaxAudioConverter/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/AaxFileCopier.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using audiamus.aux; 5 | using audiamus.aux.ex; 6 | using static audiamus.aux.Logging; 7 | 8 | namespace audiamus.aaxconv.lib { 9 | class AaxFileCopier { 10 | private readonly Book _book; 11 | private readonly IAaxCopySettings _settings; 12 | private readonly IResources _resources; 13 | 14 | private IResources R => _resources; 15 | private CallbackWrapper Callbacks { get; } 16 | 17 | public AaxFileCopier (Book book, IAaxCopySettings settings, IResources resources, CallbackWrapper callbacks) { 18 | _book = book; 19 | _settings = settings; 20 | _resources = resources; 21 | Callbacks = callbacks; 22 | } 23 | 24 | public bool Copy (Action report) { 25 | 26 | bool bookFirst = _settings.AaxCopyMode.HasFlag ((EAaxCopyMode)1); 27 | bool bookWithAuthor = _settings.AaxCopyMode.HasFlag ((EAaxCopyMode)2); 28 | bool foldersByAuthor = _settings.AaxCopyMode.HasFlag ((EAaxCopyMode)4); 29 | 30 | bool withParts = _book.PartsType != Book.EParts.none; 31 | 32 | string outdir = _settings.AaxCopyDirectory.AsUnc (); 33 | if (foldersByAuthor) { 34 | outdir = Path.Combine (outdir, _book.AuthorFile); 35 | Directory.CreateDirectory (outdir); 36 | } 37 | 38 | string stub; 39 | if (bookWithAuthor) { 40 | if (bookFirst) 41 | stub = $"{_book.TitleFile} - {_book.AuthorFile}"; 42 | else 43 | stub = $"{_book.AuthorFile} - {_book.TitleFile}"; 44 | } else 45 | stub = _book.TitleFile; 46 | 47 | bool simsBySeriesCopied = false; 48 | 49 | foreach (var part in _book.Parts) { 50 | string indir = Path.GetDirectoryName (part.AaxFileItem.FileName); 51 | 52 | if (string.Equals (indir.StripUnc (), outdir.StripUnc (), StringComparison.InvariantCultureIgnoreCase)) { 53 | Log (3, this, $"same dir, skip: indir=\"{indir.SubstitUser ()}\", outdir=\"{outdir.SubstitUser ()}\""); 54 | return true; 55 | } 56 | 57 | var sb = new StringBuilder (stub); 58 | if (withParts) 59 | sb.Append ($" ({R.PartNamePrefixStandard} {part.PartNumber})"); 60 | 61 | if (part.AaxFileItem.ContentMetadataFile is null) { 62 | var appMetadadata = new AudibleAppContentMetadata (); 63 | appMetadadata.GetContentMetadata (part, true); 64 | } 65 | 66 | var cmf = part.AaxFileItem.ContentMetadataFile; 67 | if (!(cmf?.ASIN is null)) 68 | sb.Append ($"_{cmf.ASIN}"); 69 | 70 | string ext = Path.GetExtension (part.AaxFileItem.FileName); 71 | sb.Append (ext); 72 | string filename = sb.ToString (); 73 | string audioOutfile = Path.Combine (outdir, filename); 74 | 75 | bool succ = false; 76 | try { 77 | Log (3, this, $"copy \"{part.AaxFileItem.FileName.SubstitUser ()}\" to \"{audioOutfile.SubstitUser ()}\""); 78 | succ = FileEx.Copy (part.AaxFileItem.FileName, audioOutfile, true, report, Callbacks.Cancel); 79 | } catch (Exception exc) { 80 | Log (1, this, exc.ToShortString ()); 81 | } 82 | 83 | if (!succ) 84 | return false; 85 | 86 | copyMetaFie (outdir, cmf); 87 | 88 | if (!simsBySeriesCopied) { 89 | if (part.AaxFileItem.SimsBySeriesFile is null) { 90 | var appSimsBySeries = new AudibleAppSimsBySeries (); 91 | appSimsBySeries.GetSimsBySeries (part, true); 92 | } 93 | var smf = part.AaxFileItem.SimsBySeriesFile; 94 | copyMetaFie (outdir, smf); 95 | simsBySeriesCopied = true; 96 | } 97 | } 98 | return true; 99 | } 100 | 101 | private void copyMetaFie (string outdir, AudibleAppContentMetadata.AsinJsonFile mf) { 102 | if (!(mf?.Filename is null)) { 103 | string metafile = Path.GetFileName (mf.Filename); 104 | string metaOutfile = Path.Combine (outdir, metafile); 105 | try { 106 | Log (3, this, $"copy \"{mf.Filename.SubstitUser ()}\" to \"{metaOutfile.SubstitUser ()}\""); 107 | File.Copy (mf.Filename, metaOutfile, true); 108 | } catch (Exception exc) { 109 | Log (1, this, exc.ToShortString ()); 110 | } 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/AaxFileItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using audiamus.aux.ex; 5 | using AA = audiamus.aaxconv.lib.AudibleAppContentMetadata; 6 | using static audiamus.aux.Logging; 7 | 8 | namespace audiamus.aaxconv.lib { 9 | public class AaxFileItem : IEquatable, IAudioQuality { 10 | public const string EXT_JPG = ".jpg"; 11 | public const string EXT_PNG = ".png"; 12 | public const string EXT_AAX = ".aax"; 13 | public const string EXT_AA = ".aa"; 14 | 15 | public string FileName { get; private set; } 16 | public bool HasExtAA { get; private set; } 17 | public bool IsAA { get; internal set; } 18 | public long FileSize { get; internal set; } 19 | public DateTime FileDate { get; internal set; } 20 | public string BookTitle { get; internal set; } 21 | public string [] Authors { get; internal set; } 22 | public string Author => Authors.Combine (); 23 | public string [] Narrators { get; internal set; } 24 | public string Narrator => Narrators.Combine (); 25 | public TimeSpan Duration { get; internal set; } 26 | public string Abstract { get; internal set; } 27 | public string Genre { get; internal set; } 28 | public byte[] Cover { get; internal set; } 29 | public string CoverExt { get; internal set; } 30 | public string Publisher { get; internal set; } 31 | public DateTime? PublishingDate { get; internal set; } 32 | public string Copyright { get; internal set; } 33 | public uint Channels { get; internal set; } 34 | public uint SampleRate { get; internal set; } 35 | public uint AvgBitRate { get; internal set; } 36 | public uint NumChapters { get; set; } 37 | public bool Converted { get; set; } 38 | public CustomTagFileNames CustomNames { get; set; } 39 | internal AA.AsinJsonFile ContentMetadataFile { get; set; } 40 | internal AA.AsinJsonFile SimsBySeriesFile { get; set; } 41 | 42 | public AaxFileItem (string path) { 43 | FileName = path; 44 | string ext = Path.GetExtension (path).ToLowerInvariant (); 45 | HasExtAA = ext == EXT_AA; 46 | var fi = new FileInfo (path); 47 | FileSize = fi.Length; 48 | FileDate = fi.LastWriteTime; 49 | 50 | bool succ = TagAndFileNamingHelper.ReadMetaData (this); 51 | if (!succ) { 52 | Log (1, this, $"{path.SubstitUser ()}, error reading meta data"); 53 | throw new IOException (path.SubstitUser ()); 54 | } 55 | } 56 | 57 | public override string ToString () { 58 | return $"{Author} - {BookTitle}"; 59 | } 60 | 61 | public bool Equals (AaxFileItem other) { 62 | //Check whether the compared objects reference the same data. 63 | if (Object.ReferenceEquals (this, other)) 64 | return true; 65 | 66 | //Check whether any of the compared objects is null. 67 | if (other is null) 68 | return false; 69 | 70 | //Check whether the items' properties are equal. 71 | return string.Equals (this.FileName, other.FileName, StringComparison.InvariantCultureIgnoreCase); 72 | } 73 | 74 | public override int GetHashCode () { 75 | //Get hash code for the FileName field if it is not null. 76 | int hashFileName = FileName is null ? 0 : FileName.GetHashCode (); 77 | 78 | //Calculate the hash code for the product. 79 | return hashFileName; 80 | } 81 | 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/ActivationCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using audiamus.aaxconv.lib.ex; 6 | using static audiamus.aux.Logging; 7 | 8 | namespace audiamus.aaxconv.lib { 9 | interface IActivationCode { 10 | IEnumerable ActivationCodes { get; } 11 | bool HasActivationCode { get; } 12 | } 13 | 14 | class ActivationCode : IActivationCode { 15 | 16 | private readonly IActivationSettings _settings; 17 | private List _activationCodes = new List (); 18 | 19 | public IEnumerable NumericCodes => _activationCodes?.Select (s => Convert.ToUInt32 (s, 16)).ToList(); 20 | public IEnumerable ActivationCodes => _activationCodes; 21 | public bool HasActivationCode => ActivationCodes?.Count () > 0; 22 | 23 | public ActivationCode (IActivationSettings settings) { 24 | _settings = settings; 25 | init (); 26 | } 27 | 28 | private void init () { 29 | _activationCodes.Clear (); 30 | 31 | if (_settings.ActivationCode.HasValue) { 32 | Log (2, this, "add from user settings"); 33 | _activationCodes.Add (_settings.ActivationCode.Value.ToHexString ()); 34 | } 35 | 36 | { 37 | ActivationCodeRegistry registryCodes = new ActivationCodeRegistry (); 38 | if (registryCodes.HasActivationCode) { 39 | Log (2, this, $"add from registry (#={registryCodes.ActivationCodes.Count()})"); 40 | _activationCodes = _activationCodes.Union (registryCodes.ActivationCodes).ToList (); 41 | } 42 | } 43 | 44 | { 45 | ActivationCodeApp appCodes = new ActivationCodeApp (); 46 | if (appCodes.HasActivationCode) { 47 | Log (2, this, $"add from app (#={appCodes.ActivationCodes.Count()})"); 48 | _activationCodes = _activationCodes.Union (appCodes.ActivationCodes).ToList (); 49 | } 50 | } 51 | 52 | Log (2, this, $"#unique={_activationCodes.Count}"); 53 | } 54 | 55 | public bool ReinitActivationCode () { 56 | init (); 57 | return HasActivationCode; 58 | } 59 | } 60 | 61 | namespace ex { 62 | public static class ActivationCodeEx { 63 | public static string ToHexString (this uint code) { 64 | return code.ToString ("X8"); 65 | } 66 | 67 | public static string ToHexDashString (this uint? code) { 68 | if (code.HasValue) 69 | return code.Value.ToHexDashString (); 70 | else 71 | return string.Empty; 72 | } 73 | 74 | public static string ToHexDashString (this uint code) { 75 | var bytes = BitConverter.GetBytes (code); 76 | Array.Reverse (bytes); 77 | var sb = new StringBuilder (); 78 | foreach (byte b in bytes) { 79 | if (sb.Length > 0) 80 | sb.Append ('-'); 81 | sb.Append (b.ToString ("X2")); 82 | } 83 | return sb.ToString (); 84 | } 85 | 86 | public static uint ToUInt32 (this IEnumerable chars) { 87 | if (chars.Count () == 4) { 88 | var sb = new StringBuilder (); 89 | foreach (string s in chars) 90 | sb.Append (s); 91 | try { 92 | return Convert.ToUInt32 (sb.ToString (), 16); 93 | } catch (Exception) { 94 | return 0; 95 | } 96 | } else 97 | return 0; 98 | } 99 | 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/ActivationCodeApp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using audiamus.aaxconv.lib.ex; 6 | using audiamus.aux; 7 | 8 | namespace audiamus.aaxconv.lib { 9 | class ActivationCodeApp : IActivationCode { 10 | 11 | const string PACKAGES = "Packages"; 12 | const string AUDIBLEINC_AUDIBLE = "AudibleInc.Audible"; 13 | const string LOCAL_STATE = "LocalState"; 14 | const string AUDIBLEACTIVATION_SYS = "AudibleActivation.sys"; 15 | 16 | readonly IEnumerable _activationCodes; 17 | 18 | public IEnumerable ActivationCodes => _activationCodes; 19 | public bool HasActivationCode => ActivationCodes?.Count () > 0; 20 | 21 | 22 | public ActivationCodeApp () => _activationCodes = getCodes (); 23 | 24 | public static IEnumerable GetPackageDirectories () { 25 | string path = Path.Combine (ApplEnv.LocalDirectoryRoot, PACKAGES); 26 | if (!Directory.Exists (path)) 27 | return null; 28 | string[] dirs = Directory.GetDirectories (path, $"{AUDIBLEINC_AUDIBLE}*"); 29 | List dirInfos = new List (); 30 | foreach (var dir in dirs) { 31 | string dirLocalState = Path.Combine (dir, LOCAL_STATE); 32 | if (Directory.Exists (dirLocalState)) 33 | dirInfos.Add (new DirectoryInfo (dirLocalState)); 34 | } 35 | dirInfos.Sort ((x, y) => 36 | DateTime.Compare (y.LastWriteTimeUtc, x.LastWriteTimeUtc)); 37 | 38 | return dirInfos.Select (di => di.FullName); 39 | } 40 | 41 | private static IEnumerable getCodes () { 42 | string path = Path.Combine (ApplEnv.LocalDirectoryRoot, PACKAGES); 43 | if (!Directory.Exists (path)) 44 | return null; 45 | string[] dirs = Directory.GetDirectories (path, $"{AUDIBLEINC_AUDIBLE}*"); 46 | List fileInfos = new List(); 47 | foreach (var dir in dirs) { 48 | string file = Path.Combine (dir, LOCAL_STATE, AUDIBLEACTIVATION_SYS); 49 | if (File.Exists (file)) 50 | fileInfos.Add (new FileInfo (file)); 51 | } 52 | fileInfos.Sort ((x, y) => 53 | DateTime.Compare (y.LastWriteTimeUtc, x.LastWriteTimeUtc)); 54 | 55 | List result = new List (); 56 | foreach (var fi in fileInfos) 57 | getCode (fi.FullName, result); 58 | 59 | return result; 60 | } 61 | 62 | private static void getCode (string path, List result) { 63 | using (var reader = new BinaryReader (File.OpenRead (path))) { 64 | try { 65 | uint code = reader.ReadUInt32 (); 66 | 67 | string hex = code.ToHexString (); 68 | 69 | if (result.IndexOf (hex) < 0) 70 | result.Add (hex); 71 | 72 | } catch (EndOfStreamException) { } 73 | } 74 | } 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/ActivationCodeRegistry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using audiamus.aaxconv.lib.ex; 5 | using audiamus.aux; 6 | using Microsoft.Win32; 7 | 8 | namespace audiamus.aaxconv.lib { 9 | class ActivationCodeRegistry : IActivationCode { 10 | 11 | const string SOFTWARE = "SOFTWARE"; 12 | const string WOW6432NODE = "Wow6432Node"; 13 | const string AUDIBLE = "Audible"; 14 | const string SWGIDMAP = "SWGIDMAP"; 15 | 16 | readonly IEnumerable _registryActivationCodes; 17 | 18 | public IEnumerable RegistryCodes => _registryActivationCodes?.Select (s => Convert.ToUInt32 (s, 16)).ToList(); 19 | public IEnumerable ActivationCodes => _registryActivationCodes; 20 | public bool HasActivationCode => ActivationCodes?.Count () > 0; 21 | 22 | 23 | public ActivationCodeRegistry () => _registryActivationCodes = getBytes (); 24 | 25 | private static IEnumerable getBytes () { 26 | var activationBytes = new List (); 27 | var rk = getKey (); 28 | if (rk is null) 29 | rk = getKey (true); 30 | if (rk is null) 31 | return null; 32 | 33 | using (rk) { 34 | var valNames = rk.GetValueNames (); 35 | 36 | for (int i = valNames.Length - 1; i >= 0; i--) { 37 | bool succ = uint.TryParse (valNames[i], out uint k); 38 | if (!succ) 39 | continue; 40 | if (k > 8) 41 | continue; 42 | byte[] bytes = rk.GetValue (valNames[i]) as byte[]; 43 | if (bytes is null || bytes.Length < 4) 44 | continue; 45 | uint val = BitConverter.ToUInt32 (bytes, 0); 46 | if (val == 0xffffffff) 47 | continue; 48 | 49 | string hex = val.ToHexString (); 50 | 51 | if (activationBytes.IndexOf (hex) < 0) 52 | activationBytes.Add (hex); 53 | } 54 | 55 | return activationBytes; 56 | } 57 | } 58 | 59 | private static RegistryKey getKey (bool wow = false) { 60 | RegistryKey hklm = Registry.LocalMachine; 61 | string keyPath; 62 | if (wow) 63 | keyPath = $"{SOFTWARE}\\{WOW6432NODE}\\{AUDIBLE}\\{SWGIDMAP}"; 64 | else 65 | keyPath = $"{SOFTWARE}\\{AUDIBLE}\\{SWGIDMAP}"; 66 | var key = hklm.OpenSubKey (keyPath); 67 | 68 | //Logging.Log (3, typeof (ActivationCodeRegistry), $"{hklm.Name}\\{keyPath} exists: {!(key is null)}"); 69 | 70 | if (key is null) 71 | return null; 72 | 73 | if (key.GetValueNames().Length == 0) { 74 | //Logging.Log (3, typeof (ActivationCodeRegistry), $"{hklm.Name}\\{keyPath}: exists, but no values"); 75 | key.Dispose (); 76 | return null; 77 | } 78 | 79 | return key; 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/AudioMeta.cs: -------------------------------------------------------------------------------- 1 | namespace audiamus.aaxconv.lib { 2 | class AudioMeta { 3 | public readonly TimeInterval Time = new TimeInterval (); 4 | public uint Channels { get; set; } 5 | public uint Samplerate { get; set; } 6 | public uint AvgBitRate { get; set; } 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/Book.Progress.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using audiamus.aux.ex; 4 | 5 | namespace audiamus.aaxconv.lib { 6 | partial class Book { 7 | public class ProgressData { 8 | 9 | private readonly static IReadOnlyDictionary __phaseWeights = new Dictionary { 10 | { EProgressPhase.none, 0 }, 11 | { EProgressPhase.silence, 3 }, 12 | { EProgressPhase.adjust, 2 }, 13 | { EProgressPhase.transcoding, 2 }, 14 | { EProgressPhase.copying, 1 }, 15 | }; 16 | 17 | private readonly static IReadOnlyDictionary __phaseWeightsTranscode = new Dictionary { 18 | { EProgressPhase.none, 0 }, 19 | { EProgressPhase.silence, 3 }, 20 | { EProgressPhase.adjust, 2 }, 21 | { EProgressPhase.transcoding, 10 }, 22 | { EProgressPhase.copying, 1 }, 23 | }; 24 | 25 | private readonly List<(EProgressPhase phase, int wght)> _weightedPhases = new List<(EProgressPhase, int)> (); 26 | private int _idx = -1; 27 | 28 | private readonly bool _transcode; 29 | private readonly int _numParts; 30 | 31 | public EProgressPhase CurrrentPhase => (_idx >= 0 && _weightedPhases.Count > _idx) ? _weightedPhases[_idx].phase : EProgressPhase.none; 32 | public int CurrentPhaseWeightPart => (_idx >= 0 && _weightedPhases.Count > _idx) ? _weightedPhases[_idx].wght : 0; 33 | public int CurrentPhaseWeightBook => CurrentPhaseWeightPart * _numParts; 34 | 35 | public ProgressData (int numParts, bool transcode) { 36 | _numParts = numParts; 37 | _transcode = transcode; 38 | } 39 | 40 | public void AddRange (IEnumerable phases) => phases.ForEach (ph => Add (ph)); 41 | 42 | public void Add (EProgressPhase phase) { 43 | var dict = _transcode ? __phaseWeightsTranscode : __phaseWeights; 44 | int weight = 0; 45 | dict.TryGetValue (phase, out weight); 46 | _weightedPhases.Add ((phase, weight)); 47 | } 48 | 49 | public EProgressPhase NextPhase () { 50 | _idx++; 51 | return CurrrentPhase; 52 | } 53 | 54 | public int TotalPhases () => _weightedPhases.Count * _numParts; 55 | public int TotalPhaseWeights () => _weightedPhases.Select (wp => wp.wght).Sum () * _numParts; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/CallbackWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using audiamus.aux; 4 | 5 | namespace audiamus.aaxconv.lib { 6 | 7 | class CallbackWrapper { 8 | readonly CancellationToken _token; 9 | readonly IProgress _progress; 10 | readonly IInteractionCallback _interaction; 11 | 12 | public CancellationToken CancellationToken => _token; 13 | public bool Cancelled => _token != null ? _token.IsCancellationRequested : false; 14 | 15 | public CallbackWrapper (CancellationToken token, IProgress progress, IInteractionCallback interaction = null) { 16 | _token = token; 17 | _progress = progress; 18 | _interaction = interaction; 19 | } 20 | 21 | public bool Cancel () { 22 | return _token != null ? _token.IsCancellationRequested : false; 23 | } 24 | 25 | public void Progress (ProgressMessage msg) { 26 | _progress?.Report (msg); 27 | } 28 | 29 | public bool? Interact (string msg, ECallbackType type) { 30 | return Interact (new InteractionMessage { Message = msg, Type = type }); 31 | } 32 | 33 | public bool? Interact (InteractionMessage msg) { 34 | return _interaction?.Interact (msg); 35 | } 36 | 37 | public bool? Interact (EInteractionCustomCallback type) { 38 | return _interaction?.Interact (new InteractionMessage { Type = ECallbackType.custom, Custom = type }); 39 | } 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/ChainPunctuation.cs: -------------------------------------------------------------------------------- 1 | using audiamus.aux; 2 | 3 | namespace audiamus.aaxconv.lib { 4 | public class ChainPunctuationBracket : ChainPunctuation { 5 | public override string Prefix => "<"; 6 | public override string Suffix => ">"; 7 | public override string[] Infix => null; 8 | } 9 | 10 | public class ChainPunctuationDash : ChainPunctuationBracket { 11 | public override string[] Infix => new[] { " - " }; 12 | } 13 | 14 | public class ChainPunctuationDot : ChainPunctuationBracket { 15 | public override string[] Infix => new[] { "." , "(", ")"}; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/ChapteredTracks.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace audiamus.aaxconv.lib { 4 | 5 | class ChapteredTracks { 6 | public class PartChapter { 7 | public Chapter Chapter { get; private set; } 8 | public uint ChapterNumber { get; private set; } 9 | public uint TrackNumberOffset { get; private set; } 10 | public List Tracks { get; } = new List (); 11 | 12 | public PartChapter (Chapter chapter, uint chapterNumber, uint trackNumberOffset) { 13 | Chapter = chapter; 14 | ChapterNumber = chapterNumber; 15 | TrackNumberOffset = trackNumberOffset; 16 | } 17 | } 18 | 19 | public class PartChapters { 20 | 21 | public Book.Part Part { get; private set; } 22 | public List Chapters { get; } = new List (); 23 | 24 | public PartChapters (Book.Part part) { 25 | Part = part; 26 | } 27 | } 28 | 29 | public List Parts { get; } = new List (); 30 | 31 | public ChapteredTracks (Book book) { 32 | uint offsetTrack = 1; 33 | foreach (var part in book.Parts) { 34 | var partChapters = new PartChapters (part); 35 | Parts.Add (partChapters); 36 | foreach (var track in part.Tracks) { 37 | var partChapt = partChapters.Chapters.Find (pc => object.ReferenceEquals (track.Chapter, pc.Chapter)); 38 | if (partChapt is null) { 39 | partChapt = new PartChapter (track.Chapter, book.ChapterNumber(track.Chapter), offsetTrack); 40 | partChapters.Chapters.Add (partChapt); 41 | } 42 | partChapt.Tracks.Add (track); 43 | } 44 | offsetTrack += (uint)(part.Tracks?.Count ?? 0); 45 | } 46 | } 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/ContentMetaDataJson.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 audiamus.aaxconv.lib.json { 8 | public class Chapter { 9 | public int length_ms { get; set; } 10 | public int start_offset_ms { get; set; } 11 | public int start_offset_sec { get; set; } 12 | public string title { get; set; } 13 | } 14 | 15 | public class ChapterInfo { 16 | public int brandIntroDurationMs { get; set; } 17 | public int brandOutroDurationMs { get; set; } 18 | public List chapters { get; set; } 19 | public int runtime_length_ms { get; set; } 20 | public int runtime_length_sec { get; set; } 21 | } 22 | 23 | public class ContentReference { 24 | public string acr { get; set; } 25 | public string asin { get; set; } 26 | public string content_format { get; set; } 27 | public int content_size_in_bytes { get; set; } 28 | public string marketplace { get; set; } 29 | public string sku { get; set; } 30 | public string tempo { get; set; } 31 | public string version { get; set; } 32 | } 33 | 34 | public class ContentMetadata { 35 | public ChapterInfo chapter_info { get; set; } 36 | public ContentReference content_reference { get; set; } 37 | } 38 | 39 | public class AppContentMetadata { 40 | public ContentMetadata content_metadata { get; set; } 41 | public List response_groups { get; set; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/ContentMetadata.json.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 audiamus.aaxconv.lib.json { 8 | public class Chapter { 9 | public int length_ms { get; set; } 10 | public int start_offset_ms { get; set; } 11 | public int start_offset_sec { get; set; } 12 | public string title { get; set; } 13 | } 14 | 15 | public class ChapterInfo { 16 | public int brandIntroDurationMs { get; set; } 17 | public int brandOutroDurationMs { get; set; } 18 | public List chapters { get; set; } 19 | public int runtime_length_ms { get; set; } 20 | public int runtime_length_sec { get; set; } 21 | } 22 | 23 | public class ContentReference { 24 | public string acr { get; set; } 25 | public string asin { get; set; } 26 | public string content_format { get; set; } 27 | public long content_size_in_bytes { get; set; } 28 | public string marketplace { get; set; } 29 | public string sku { get; set; } 30 | public string tempo { get; set; } 31 | public string version { get; set; } 32 | } 33 | 34 | public class ContentMetadata { 35 | public ChapterInfo chapter_info { get; set; } 36 | public ContentReference content_reference { get; set; } 37 | } 38 | 39 | public class AppContentMetadata { 40 | public ContentMetadata content_metadata { get; set; } 41 | public List response_groups { get; set; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/CustomTagFileNames.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace audiamus.aaxconv.lib { 5 | public class CustomTagFileNames { 6 | public string AuthorTag { get; set; } 7 | public string AuthorFile { get; set; } 8 | public string TitleTag { get; set; } 9 | public string TitleFile { get; set; } 10 | public DateTime? YearTag { get; set; } 11 | public string GenreTag { get; set; } 12 | 13 | public override string ToString () { 14 | var sb = new StringBuilder (); 15 | sb.AppendLine ($" {nameof (AuthorTag)}=\"{AuthorTag}\""); 16 | sb.AppendLine ($" {nameof (AuthorFile)}=\"{AuthorFile}\""); 17 | sb.AppendLine ($" {nameof (TitleTag)}=\"{TitleTag}\""); 18 | sb.AppendLine ($" {nameof (TitleFile)}=\"{TitleFile}\""); 19 | sb.AppendLine ($" {nameof (YearTag)}={YearTag?.Year}"); 20 | sb.Append ($" {nameof (GenreTag)}=\"{GenreTag}\""); 21 | return sb.ToString (); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/Enums.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | namespace audiamus.aaxconv.lib { 5 | public enum EConvFormat { mp3, mp4 } 6 | public enum EConvMode { single, chapters, splitChapters, splitTime} 7 | 8 | public enum EInteractionCustomCallback { none, noActivationCode } 9 | 10 | // Track file naming pattern 11 | // - - 12 | // - - 13 | // - 14 | // - 15 | public enum EFileNaming { 16 | track, 17 | track_book, 18 | track_book_author, 19 | author_book_track, 20 | book_track, 21 | } 22 | 23 | //Track title tag naming pattern 24 | // - - 25 | // - - 26 | // - 27 | // - 28 | public enum ETitleNaming { 29 | track, 30 | track_book, 31 | track_book_author, 32 | book_author, 33 | author_book, 34 | author_book_track, 35 | book_track, 36 | } 37 | 38 | //Track numbering pattern (for track file and track title) 39 | // 40 | //. 41 | public enum ETrackNumbering { 42 | track, 43 | chapter_a_track, 44 | track_b_chapter_c, 45 | //track_b_nTrks_c, 46 | //chapter_a_track_b_nTrks_c, 47 | //track_b_chapter_c_b_nTrks_c, 48 | } 49 | 50 | public enum ELongTitle { no, book_series, series_book, as_is } 51 | 52 | public enum EGeneralNaming { 53 | source, 54 | standard, 55 | custom, 56 | } 57 | 58 | public enum EGeneralNamingEx { 59 | source, 60 | standard, 61 | custom, 62 | _nofolders 63 | } 64 | 65 | public enum EFlatFolderNaming { 66 | author_book, 67 | book_author, 68 | } 69 | 70 | [Flags] 71 | [TypeConverter] 72 | public enum EAaxCopyMode { 73 | no = 0, 74 | // book_first = 1, 75 | // book_with_author = 2, 76 | // folders_by_author = 4, 77 | // folders = 8, 78 | flat__author_book = 10, 79 | flat__book_author = 11, 80 | author__book = 12, 81 | author__author_book = 14, 82 | author__book_author = 15, 83 | } 84 | 85 | public enum ENamedChapters { 86 | no, 87 | yes, 88 | yesAlwaysWithNumbers 89 | } 90 | 91 | public enum EOnlineUpdate { 92 | no, 93 | promptForDownload, 94 | promptForInstall 95 | } 96 | 97 | public enum EUpdateInteract { 98 | newVersAvail, 99 | installNow, 100 | installLater, 101 | mayAskAgain, 102 | } 103 | 104 | public enum EVerifyAdjustChapters { 105 | no = 0, 106 | splitChapterMode = 1, 107 | bothChapterModes = 2, 108 | } 109 | 110 | public enum EVerifyAdjustChapterMarks { 111 | no = 0, 112 | splitChapterOrTimeMode = 1, 113 | allModes = 2, 114 | } 115 | 116 | public enum EFixAACEncoding { 117 | no = 0, 118 | withIntermediateCopy = 1, 119 | allModes = 2, 120 | } 121 | 122 | enum ETrackDuration { 123 | Min = 3, 124 | MaxSplitChapter = 15, 125 | MaxTimeSplit = 90 126 | } 127 | 128 | public enum EReducedBitRate { 129 | off, 130 | _128k, 131 | _96k, 132 | _64k, 133 | _48k, 134 | _32k, 135 | _24k 136 | } 137 | 138 | public enum EPreferEmbeddedChapterTimes { 139 | no, 140 | ifSilent, 141 | always 142 | } 143 | 144 | public enum ERoleTag { 145 | none, 146 | artist, 147 | albumArtist, 148 | composer, 149 | conductor 150 | } 151 | 152 | public enum ERoleTagAssignment { 153 | none = 0, 154 | author = 1, 155 | author__narrator__ = 2, // DEPRECATED 156 | author_narrator = 3, // => 2 157 | __narrator__ = 4, // DEPRECATED 158 | narrator = 5 // => 3 159 | } 160 | 161 | public enum EOutFolderConflict { 162 | ask, 163 | overwrite, 164 | new_folder, 165 | skip 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Net; 4 | using System.Text.RegularExpressions; 5 | 6 | namespace audiamus.aaxconv.lib.ex { 7 | static class HtmlDecode { 8 | public static string Decode (this string s) { 9 | if (s is null) 10 | return null; 11 | return WebUtility.HtmlDecode (s); 12 | } 13 | 14 | public static string[] Decode (this string[] ss) { 15 | if (ss is null) 16 | return new string[0]; 17 | return ss.Select (Decode).ToArray (); 18 | } 19 | } 20 | 21 | public static class TrackDurationEx { 22 | public static (int min, int max, int val) TrackDuration (this byte value, EConvMode mode) { 23 | ETrackDuration maxTrackDurMins = mode == EConvMode.splitTime ? ETrackDuration.MaxTimeSplit : ETrackDuration.MaxSplitChapter; 24 | int min = (int)ETrackDuration.Min; 25 | int max = (int)maxTrackDurMins; 26 | int val = Math.Max (min, Math.Min ((int)maxTrackDurMins, value)); 27 | return (min, max, val); 28 | } 29 | } 30 | 31 | public static class EReducedBitRateEx { 32 | private static readonly Regex _rgxEnumBitrate = new Regex (@"(\d+)", RegexOptions.Compiled | RegexOptions.IgnoreCase); 33 | 34 | public static uint UInt32 (this EReducedBitRate ebitrate) { 35 | string sbitrate = ebitrate.ToString (); 36 | Match match = _rgxEnumBitrate.Match (sbitrate); 37 | if (match.Success) { 38 | if (uint.TryParse (match.Groups[1].Value, out var bitrate)) 39 | return bitrate; 40 | } 41 | return 0; 42 | } 43 | } 44 | 45 | public static class BitrateEx { 46 | public static (uint applBitrate, uint settingsBitrate) ApplicableBitRate (this IBitRateSettings settings, uint sourceBitrate) { 47 | uint settingsBitrate = settings.ReducedBitRate.UInt32 (); 48 | if ((settingsBitrate == 0 || settingsBitrate >= sourceBitrate) && !settings.VariableBitRate) 49 | return (0, 0); 50 | 51 | uint applicableBitrate = sourceBitrate; 52 | if (settingsBitrate != 0) 53 | applicableBitrate = Math.Min (sourceBitrate, settingsBitrate); 54 | 55 | return (applicableBitrate, settingsBitrate); 56 | } 57 | } 58 | 59 | public static class ConvSettingsEx { 60 | public static bool UseEmbeddedChapterTimes (this IConvSettings settings) => 61 | settings.PreferEmbeddedChapterTimes == EPreferEmbeddedChapterTimes.ifSilent && settings.NamedChapters != ENamedChapters.no; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/FileEx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using audiamus.aux.w32; 3 | 4 | namespace audiamus.aaxconv.lib { 5 | interface IFileCopyCallout { 6 | void ProcessBuffer (byte[] buffer, int size, long globalOffset); 7 | } 8 | 9 | static class FileEx { 10 | 11 | private const int BUFSIZ = 10 * 1000 * 1000; // 10 MB 12 | private const int IVL_MS = 200; 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 ThreadProgress (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/AaxAudioConverterLib/FixAtomESDS.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace audiamus.aaxconv.lib { 4 | class FixAtomESDS : IFileCopyCallout { 5 | 6 | static readonly byte[] ESDS_ATOM = {0x05,0x80,0x80,0x80,0x02}; 7 | static readonly byte[] PARA = {0x12,0x12}; 8 | static readonly byte[] PARA_FIX = {0x12,0x10}; 9 | 10 | void IFileCopyCallout.ProcessBuffer (byte[] buffer, int size, long globalOffset) { 11 | if (globalOffset > 0) 12 | return; 13 | 14 | int idxAtom = findFirstPattern (buffer, 0, size, ESDS_ATOM); 15 | if (idxAtom < 0) 16 | return; 17 | 18 | int idxPara = idxAtom + ESDS_ATOM.Length; 19 | 20 | int idx2 = findFirstPattern (buffer, idxPara, size, PARA, true); 21 | if (idx2 != idxPara) 22 | return; 23 | 24 | for (int i = 0; i < PARA_FIX.Length; i++) 25 | buffer[i + idxPara] = PARA_FIX[i]; 26 | 27 | } 28 | 29 | private static int findFirstPattern (byte[] source, int offset, int size, byte[] pattern, bool noIteration = false) { 30 | int len = Math.Min (source.Length, size); 31 | int max = len - pattern.Length; 32 | if (noIteration) 33 | max = offset + 1; 34 | for (int i = offset; i < max; i++) { 35 | for (int j = 0; j < pattern.Length; j++) { 36 | if (source[i + j] != pattern[j]) 37 | break; 38 | if (j == pattern.Length - 1) 39 | return i; 40 | } 41 | } 42 | return -1; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/Interfaces.cs: -------------------------------------------------------------------------------- 1 | namespace audiamus.aaxconv.lib { 2 | public interface IPreviewTitle { 3 | IConvSettings Settings { get; } 4 | (string tag, string file) TitlePreview (AaxFileItem fileItem); 5 | string PruneTitle (string title); 6 | string GetGenre (AaxFileItem fileItem); 7 | } 8 | 9 | public interface IAudioQuality { 10 | uint SampleRate { get; } 11 | uint AvgBitRate { get; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/ProgressMessage.cs: -------------------------------------------------------------------------------- 1 | namespace audiamus.aaxconv.lib { 2 | public enum EProgressPhase { none, silence, adjust, transcoding, copying } 3 | 4 | public class ProgressInfo { 5 | public class ProgressEntry { 6 | public T Content { get; private set; } 7 | public bool Cancel { get; private set; } 8 | 9 | public ProgressEntry (T content, bool cancel = false) { 10 | Content = content; 11 | Cancel = cancel; 12 | } 13 | } 14 | 15 | public ProgressEntry Title { get; private set; } 16 | public EProgressPhase Phase { get; private set; } 17 | public uint? PartNumber { get; private set; } 18 | public uint? NumberOfChapters { get; private set; } 19 | public uint? NumberOfTracks { get; private set; } 20 | public ProgressEntry Chapter { get; private set; } 21 | public ProgressEntry Part { get; private set; } 22 | public ProgressEntry Track { get; private set; } 23 | 24 | private ProgressInfo (string title, bool cancel = false) { 25 | Title = new ProgressEntry (title, cancel); 26 | } 27 | 28 | public static ProgressInfo ProgressInfoBook (string title, EProgressPhase phase) { 29 | var info = new ProgressInfo (title) { 30 | Phase = phase 31 | }; 32 | return info; 33 | } 34 | 35 | public static ProgressInfo ProgressInfoBookCancel (string title) { 36 | var info = new ProgressInfo (title, true); 37 | return info; 38 | } 39 | 40 | public static ProgressInfo ProgressInfoChapter (string title, uint numChapter) { 41 | var info = new ProgressInfo (title) { 42 | Chapter = new ProgressEntry (numChapter) 43 | }; 44 | return info; 45 | } 46 | 47 | public static ProgressInfo ProgressInfoChapterCancel (string title, uint numChapter) { 48 | var info = new ProgressInfo (title) { 49 | Chapter = new ProgressEntry (numChapter, true) 50 | }; 51 | return info; 52 | } 53 | 54 | 55 | public static ProgressInfo ProgressInfoTrack (string title, uint numTrack) { 56 | var info = new ProgressInfo (title) { 57 | Track = new ProgressEntry (numTrack) 58 | }; 59 | return info; 60 | } 61 | 62 | public static ProgressInfo ProgressInfoTrackCancel (string title, uint numTrack) { 63 | var info = new ProgressInfo (title) { 64 | Track = new ProgressEntry (numTrack, true) 65 | }; 66 | return info; 67 | } 68 | 69 | public static ProgressInfo ProgressInfoPart (string title, uint numPart) { 70 | var info = new ProgressInfo (title) { 71 | Part = new ProgressEntry (numPart) 72 | }; 73 | return info; 74 | } 75 | 76 | public static ProgressInfo ProgressInfoPartCancel (string title, uint numPart) { 77 | var info = new ProgressInfo (title) { 78 | Part = new ProgressEntry (numPart, true) 79 | }; 80 | return info; 81 | } 82 | 83 | public static ProgressInfo ProgressInfoBookCounters (string title, uint? numChapters, uint? numTracks = null, uint? partNum = null) { 84 | var info = new ProgressInfo (title) { 85 | PartNumber = partNum, 86 | NumberOfChapters = numChapters, 87 | NumberOfTracks = numTracks 88 | }; 89 | return info; 90 | } 91 | 92 | 93 | } 94 | 95 | public class ProgressMessage { 96 | public bool Reset; 97 | public bool ResetSteps; 98 | public uint? AddTotalWeightedPhases; 99 | public uint? IncWeightedPhases; 100 | public int? AddTotalSteps; // Note: can be negative 101 | public uint? IncSteps; 102 | public uint? IncStepsPerMille; 103 | public ProgressInfo Info; 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("AaxAudioConverterLib")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("audiamus")] 12 | [assembly: AssemblyProduct("AaxAudioConverterLib")] 13 | [assembly: AssemblyCopyright("Copyright © 2019 - 2023 audiamus")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("724c151f-65e8-4108-8cfb-ae2fd4c63033")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion ("1.18.2.0")] 36 | [assembly: AssemblyFileVersion ("1.18.2.0")] 37 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/ResourceInterface.cs: -------------------------------------------------------------------------------- 1 | namespace audiamus.aaxconv.lib { 2 | public interface IResources { 3 | string MsgFFmpegVersion1 { get; }// AaxAudioConverter has been tested against FFmpeg version xxxx 4 | string MsgFFmpegVersion2 { get; }// The located version is xxxx 5 | string MsgFFmpegVersion3 { get; }// Try with this version? 6 | string MsgFFmpegVersion4 { get; }// It can always be altered in the basic settings (via the system menu). 7 | 8 | string MsgActivationError1 { get; } //Activation Error for 9 | string MsgActivationError2 { get; } //Enter a different code. 10 | string MsgActivationError3 { get; } //Will be skipped. 11 | 12 | string MsgInvalidInternalFileType { get; } //Not an AAX or AA file internally. 13 | 14 | string MsgDirectoryCreationCallback { get; } //exists and is not empty.\r\n" + 15 | //"Override content, new folder or skip book?\r\n" + 16 | //"[Yes]: Override content\r\n" + 17 | //"[No]: New folder\r\n" + 18 | //"[Cancel]: Skip book" 19 | string MsgDirectoryPartCreationCallback { get; } //exists and is not empty.\r\n" + 20 | string MsgDirectoryCreationCallbackForAll { get; } 21 | 22 | string PartNames { get; } 23 | string PartNamePrefixStandard { get; } 24 | string ChapterNamePrefixStandard { get; } 25 | 26 | //string MsgOnlineUpdateNewVersion { get; } 27 | //string MsgOnlineUpdateDownload { get; } 28 | //string MsgOnlineUpdateInstall { get; } 29 | //string MsgOnlineUpdateInstallNow { get; } 30 | //string MsgOnlineUpdateInstallLater { get; } 31 | 32 | string HdrAuthor { get; } 33 | string HdrTitle { get; } 34 | string HdrNarrator { get; } 35 | string HdrDuration { get; } 36 | string HdrYear { get; } 37 | string HdrPublisher { get; } 38 | string HdrCopyright { get; } 39 | string HdrGenre { get; } 40 | string HdrSampleRate { get; } 41 | string HdrBitRate { get; } 42 | 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/SeriesTitles.json.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 audiamus.aaxconv.lib.json { 8 | 9 | 10 | public class AppSeriesTitles { 11 | public string[] response_groups { get; set; } 12 | public SimilarProducts[] similar_products { get; set; } 13 | } 14 | 15 | public class SimilarProducts : Product { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/SettingsInterface.cs: -------------------------------------------------------------------------------- 1 | using audiamus.aux.diagn; 2 | 3 | namespace audiamus.aaxconv.lib { 4 | public interface INamingSettings : ITitleNamingSettings { 5 | EFileNaming FileNaming { get; set; } 6 | ETitleNaming TitleNaming { get; set; } 7 | ETrackNumbering TrackNumbering { get; set; } 8 | bool TotalTracks { get; set; } 9 | EGeneralNaming GenreNaming { get; set; } 10 | string GenreName { get; set; } 11 | EGeneralNamingEx ChapterNaming { get; set; } 12 | string ChapterName { get; set; } 13 | } 14 | 15 | public interface INamingSettingsEx : INamingSettings { 16 | EGeneralNaming PartNaming { get; set; } 17 | string PartName { get; set; } 18 | bool ExtraMetaFiles { get; set; } 19 | ENamedChapters NamedChapters { get; set; } 20 | bool M4B { get; set; } 21 | } 22 | 23 | public interface IActivationSettings { 24 | [ToString (typeof(ToStringConverterActivationCode))] 25 | uint? ActivationCode { get; set; } 26 | } 27 | 28 | public interface ITitleNamingSettings { 29 | bool SeriesTitleLeft { get; set; } 30 | ELongTitle LongBookTitle { get; set; } 31 | } 32 | 33 | 34 | public interface ITitleSettingsEx : ITitleNamingSettings { 35 | string AddnlValTitlePunct { get; set; } 36 | } 37 | 38 | public interface IUpdateSetting { 39 | EOnlineUpdate OnlineUpdate { get; set; } 40 | string OnlineUpdateOthersDeclined { get; set; } 41 | } 42 | 43 | public interface IAaxCopySettings { 44 | EAaxCopyMode AaxCopyMode{ get; set; } 45 | [ToString (typeof(ToStringConverterPath))] 46 | string AaxCopyDirectory{ get; set; } 47 | } 48 | 49 | public interface IModeSettings { 50 | EConvFormat ConvFormat { get; set; } 51 | EConvMode ConvMode { get; set; } 52 | } 53 | 54 | public interface INamingAndModeSettings : INamingSettingsEx, IModeSettings { 55 | } 56 | 57 | public interface IBitRateSettings : IModeSettings { 58 | bool VariableBitRate { get; set; } 59 | EReducedBitRate ReducedBitRate { get; set; } 60 | } 61 | 62 | public interface IRoleTagAssigmentSettings { 63 | bool? Narrator { get; set; } 64 | 65 | ERoleTagAssignment TagArtist { get; set; } 66 | ERoleTagAssignment TagAlbumArtist { get; set; } 67 | ERoleTagAssignment TagComposer { get; set; } 68 | ERoleTagAssignment TagConductor { get; set; } 69 | } 70 | 71 | public interface IConvSettings : 72 | INamingAndModeSettings, IActivationSettings, ITitleSettingsEx, 73 | IUpdateSetting, IAaxCopySettings, IBitRateSettings, 74 | IRoleTagAssigmentSettings { 75 | bool NonParallel { get; } 76 | int FFmpeg64bitHours { get; } 77 | [ToString (typeof (ToStringConverterPath))] 78 | string InputDirectory { get; set; } 79 | [ToString (typeof (ToStringConverterPath))] 80 | string OutputDirectory { get; set; } 81 | [ToString (typeof (ToStringConverterPath))] 82 | string FFMpegDirectory { get; set; } 83 | bool RelaxedFFmpegVersionCheck { get; set; } 84 | bool ConvertByFileDate { get; set; } 85 | byte TrkDurMins { get; set; } 86 | string PartNames { get; set; } 87 | string Genres { get; set; } 88 | bool FlatFolders { get; set; } 89 | EFlatFolderNaming FlatFolderNaming { get; set; } 90 | bool WithSeriesTitle { get; set; } 91 | byte NumDigitsSeriesSeqNo { get; set; } 92 | bool FullCaptionBookFolder { get; set; } 93 | EOutFolderConflict OutFolderConflict {get; set;} 94 | uint ShortChapterSec { get; set; } 95 | uint VeryShortChapterSec { get; set; } 96 | EVerifyAdjustChapterMarks VerifyAdjustChapterMarks { get; set; } 97 | EPreferEmbeddedChapterTimes PreferEmbeddedChapterTimes { get; set; } 98 | bool Latin1EncodingForPlaylist { get; set; } 99 | bool IntermedCopySingle { get; set; } 100 | EFixAACEncoding FixAACEncoding { get; set; } 101 | bool AutoLaunchPlayer { get; set; } 102 | string Version { get; set; } 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/SimsBySeries.json.cs: -------------------------------------------------------------------------------- 1 | namespace audiamus.aaxconv.lib.json { 2 | 3 | 4 | public class AppSimsBySeries { 5 | public Product product { get; set; } 6 | public string[] response_groups { get; set; } 7 | } 8 | 9 | public class Product { 10 | public string asin { get; set; } 11 | public Author[] authors { get; set; } 12 | public AvailableCodecs[] available_codecs { get; set; } 13 | public string content_delivery_type { get; set; } 14 | public string content_type { get; set; } 15 | public string format_type { get; set; } 16 | public bool has_children { get; set; } 17 | public bool is_adult_product { get; set; } 18 | public bool is_listenable { get; set; } 19 | public string issue_date { get; set; } 20 | public string language { get; set; } 21 | public string merchandising_summary { get; set; } 22 | public Narrator[] narrators { get; set; } 23 | public ProductImages product_images { get; set; } 24 | public string publisher_name { get; set; } 25 | public Rating rating { get; set; } 26 | public string release_date { get; set; } 27 | public int runtime_length_min { get; set; } 28 | public string sample_url { get; set; } 29 | public Series[] series { get; set; } 30 | public string sku { get; set; } 31 | public string sku_lite { get; set; } 32 | public string subtitle { get; set; } 33 | public string[] thesaurus_subject_keywords { get; set; } 34 | public string title { get; set; } 35 | public string publication_name { get; set; } 36 | } 37 | 38 | public class ProductImages { 39 | public string _300 { get; set; } 40 | } 41 | 42 | public class Rating { 43 | public int num_reviews { get; set; } 44 | public OverallDistribution overall_distribution { get; set; } 45 | public PerformanceDistribution performance_distribution { get; set; } 46 | public StoryDistribution story_distribution { get; set; } 47 | } 48 | 49 | public class OverallDistribution { 50 | public float average_rating { get; set; } 51 | public string display_average_rating { get; set; } 52 | public float display_stars { get; set; } 53 | public int num_five_star_ratings { get; set; } 54 | public int num_four_star_ratings { get; set; } 55 | public int num_one_star_ratings { get; set; } 56 | public int num_ratings { get; set; } 57 | public int num_three_star_ratings { get; set; } 58 | public int num_two_star_ratings { get; set; } 59 | } 60 | 61 | public class PerformanceDistribution { 62 | public float average_rating { get; set; } 63 | public string display_average_rating { get; set; } 64 | public float display_stars { get; set; } 65 | public int num_five_star_ratings { get; set; } 66 | public int num_four_star_ratings { get; set; } 67 | public int num_one_star_ratings { get; set; } 68 | public int num_ratings { get; set; } 69 | public int num_three_star_ratings { get; set; } 70 | public int num_two_star_ratings { get; set; } 71 | } 72 | 73 | public class StoryDistribution { 74 | public float average_rating { get; set; } 75 | public string display_average_rating { get; set; } 76 | public float display_stars { get; set; } 77 | public int num_five_star_ratings { get; set; } 78 | public int num_four_star_ratings { get; set; } 79 | public int num_one_star_ratings { get; set; } 80 | public int num_ratings { get; set; } 81 | public int num_three_star_ratings { get; set; } 82 | public int num_two_star_ratings { get; set; } 83 | } 84 | 85 | public class Author { 86 | public string asin { get; set; } 87 | public string name { get; set; } 88 | } 89 | 90 | public class AvailableCodecs { 91 | public string enhanced_codec { get; set; } 92 | public string format { get; set; } 93 | public bool is_kindle_enhanced { get; set; } 94 | public string name { get; set; } 95 | } 96 | 97 | public class Narrator { 98 | public string name { get; set; } 99 | } 100 | 101 | public class Series { 102 | public string asin { get; set; } 103 | public string sequence { get; set; } 104 | public string title { get; set; } 105 | public string url { get; set; } 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/TagAndFileNamingHelper.Numbers.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using audiamus.aux.ex; 3 | 4 | namespace audiamus.aaxconv.lib { 5 | partial class TagAndFileNamingHelper { 6 | class Numbers { 7 | public readonly int nTrk = -1; // current track (in this part/all parts) 8 | public readonly int nTrks = -1; // total tracks (in this part/all parts) 9 | public readonly int nnTrk = -1; // track digits (in this part/all parts) 10 | 11 | public readonly int nChTrk = -1; // current track in chapter 12 | public readonly int nnChTrk = -1; // chapter track digits 13 | public readonly int nChTrks = -1; // chapter track digits 14 | 15 | public readonly int nDsk = -1; // current disk 16 | public readonly int nDsks = -1; // total disks 17 | 18 | public readonly int nChp = -1; // current chapter (in this part/all parts) 19 | public readonly int nnChp = -1; // chapter digits (in this part/all parts) 20 | 21 | public readonly int nPrt = -1; // current part 22 | public readonly int nnPrt = -1; // part digits 23 | 24 | public Numbers (Track track, Book.Part part) { 25 | Book book = part.Book; 26 | 27 | this.nPrt = part.PartNumber; 28 | this.nnPrt = book.Parts.Select (p => p.PartNumber).Max ().Digits (); 29 | 30 | if (!(track is null)) { 31 | var chapterTracks = part.Tracks?.Where (t => !(track.Chapter is null) && object.ReferenceEquals (t.Chapter, track.Chapter)).ToList (); 32 | this.nChTrk = (chapterTracks?.IndexOf (track) ?? -1) + 1; 33 | this.nChTrks = chapterTracks?.Count ?? 0; 34 | this.nnChTrk = this.nChTrks.Digits (); 35 | } 36 | 37 | if (book.PartsType == Book.EParts.some) { 38 | this.nTrk = (part.Tracks?.IndexOf (track) ?? -1) + 1; 39 | this.nTrks = part.Tracks?.Count ?? 0; 40 | 41 | this.nDsk = part.PartNumber; 42 | this.nDsks = 0; 43 | 44 | this.nChp = (part.Chapters?.IndexOf (track?.Chapter) ?? -1) + 1; 45 | this.nnChp = part.Chapters?.Count.Digits () ?? 0; 46 | 47 | } else { 48 | 49 | this.nTrk = book.Parts.Select (pt => 50 | { 51 | if (pt != part) { 52 | if (pt.PartNumber < part.PartNumber) 53 | return pt.Tracks?.Count ?? 0; 54 | else 55 | return 0; 56 | } else 57 | return (part.Tracks?.IndexOf (track) ?? -1) + 1; 58 | }).Sum (); 59 | 60 | this.nTrks = book.Parts.Select (p => p.Tracks?.Count () ?? 0).Sum (); 61 | 62 | this.nDsks = book.Parts.Count; 63 | 64 | 65 | this.nChp = book.Parts.Select (pt => 66 | { 67 | if (pt != part) { 68 | if (pt.PartNumber < part.PartNumber) 69 | return pt.Chapters?.Count ?? 0; 70 | else 71 | return 0; 72 | } else { 73 | if (track?.Chapter is null) 74 | return 0; 75 | else 76 | return (pt.Chapters?.IndexOf (track?.Chapter) ?? -1) + 1; 77 | } 78 | }).Sum (); 79 | 80 | this.nnChp = book.Parts.Select (p => p.Chapters?.Count ?? 0).Sum ().Digits (); 81 | this.nDsk = book.PartsType == Book.EParts.none ? 1 : part.PartNumber; 82 | } 83 | 84 | this.nnTrk = this.nTrks.Digits (); 85 | 86 | } 87 | 88 | } 89 | } 90 | } 91 | 92 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/ThreadProgress.cs: -------------------------------------------------------------------------------- 1 | #define xEXTRA 2 | 3 | using System; 4 | #if EXTRA 5 | using static audiamus.aux.Logging; 6 | #endif 7 | 8 | namespace audiamus.aaxconv.lib { 9 | 10 | class ThreadProgress : IDisposable { 11 | #if EXTRA 12 | const int LVL = 3; 13 | 14 | private static int __id = 0; 15 | private readonly int _id = ++__id; 16 | 17 | private string ID => $"{{#{_id}}} "; 18 | #endif 19 | 20 | const int _1000 = 1000; 21 | readonly Action _report; 22 | 23 | private int _valuePerMille; 24 | 25 | public ThreadProgress (Action report) { 26 | #if EXTRA 27 | Log (LVL, this, () => ID); 28 | #endif 29 | _report = report; 30 | } 31 | 32 | public void Dispose () { 33 | #if EXTRA 34 | Log (LVL, this, () => ID); 35 | #endif 36 | int inc = _1000 - _valuePerMille; 37 | if (inc > 0) { 38 | #if EXTRA 39 | Log (LVL, this, () => $"{ID}{inc}"); 40 | #endif 41 | _report?.Invoke (new ProgressMessage { 42 | IncStepsPerMille = (uint)inc 43 | }); 44 | } 45 | } 46 | 47 | public void Report (double value) { 48 | #if EXTRA 49 | Log (LVL, this, () => $"{ID}val={value}"); 50 | #endif 51 | int val = (int)(value * _1000); 52 | int total = Math.Min (_1000, val); 53 | int inc = total - _valuePerMille; 54 | _valuePerMille = total; 55 | if (inc > 0) { 56 | #if EXTRA 57 | Log (LVL, this, () => $"{ID}{inc}"); 58 | #endif 59 | _report?.Invoke (new ProgressMessage { 60 | IncStepsPerMille = (uint)inc 61 | }); 62 | } 63 | } 64 | 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/TimeInterval.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using audiamus.aux.ex; 3 | 4 | namespace audiamus.aaxconv.lib { 5 | interface ITimeInterval { 6 | TimeSpan Begin { get; } 7 | TimeSpan End { get; } 8 | TimeSpan Duration { get; } 9 | } 10 | 11 | class TimeInterval : ITimeInterval { 12 | private TimeSpan _begin; 13 | private TimeSpan _end; 14 | private TimeSpan _duration; 15 | 16 | public TimeSpan Begin { 17 | get => _begin; 18 | set 19 | { 20 | _begin = value; 21 | if (_begin > _end) 22 | _end = _begin; 23 | _duration = _end - _begin; 24 | } 25 | } 26 | 27 | public TimeSpan End { 28 | get => _end; 29 | set 30 | { 31 | _end = value; 32 | if (_end < _begin) 33 | _begin = _end; 34 | _duration = _end - _begin; 35 | } 36 | } 37 | 38 | public TimeSpan Duration { 39 | get => _duration; 40 | set { 41 | _duration = value; 42 | _begin = TimeSpan.Zero; 43 | _end = _duration; 44 | } 45 | } 46 | 47 | public TimeInterval () { } 48 | 49 | public TimeInterval (TimeSpan duration) { 50 | _end = duration; 51 | _duration = duration; 52 | } 53 | 54 | public TimeInterval (TimeSpan begin, TimeSpan end) { 55 | _begin = begin; 56 | _end = end; 57 | if (_end > _begin) 58 | _duration = end - begin; 59 | } 60 | 61 | public TimeInterval (TimeInterval other, TimeSpan offset = default) { 62 | _begin = other.Begin + offset; 63 | _end = other.End + offset; 64 | if (_end > _begin) 65 | _duration = _end - _begin; 66 | } 67 | 68 | public TimeInterval Shifted (TimeSpan offset) => new TimeInterval (Begin + offset, End + offset); 69 | 70 | public override string ToString () { 71 | return $"{Begin.ToStringHMSm()} -> {End.ToStringHMSm()} ({Duration.ToStringHMSm()})"; 72 | } 73 | 74 | public string ToString (TimeSpan offset) => 75 | $"[abs: {(Begin+offset).ToStringHMSm()} -> {(End+offset).ToStringHMSm()}]"; 76 | 77 | 78 | public string ToStringEx () => ToString() + $" [{Begin.TotalSeconds,10:000000.000} {End.TotalSeconds,10:000000.000}]"; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/ToStringConverters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using audiamus.aux.diagn; 3 | using audiamus.aux.ex; 4 | 5 | namespace audiamus.aaxconv.lib { 6 | 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 | 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/AaxAudioConverterLib/Track.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using audiamus.aux.ex; 4 | 5 | namespace audiamus.aaxconv.lib { 6 | 7 | 8 | enum ETrackState { initial, current, complete, aborted } 9 | 10 | interface ITrack { 11 | IChapter Chapter { get; } 12 | ITimeInterval Time { get; } 13 | string FileName { get; } 14 | string Title { get; } 15 | bool HasMinDuration { get; } 16 | } 17 | 18 | class Track : ITrack { 19 | static readonly TimeSpan MIN_DURATION = TimeSpan.FromMilliseconds (Chapter.MS_MIN_CHAPTER_LENGTH); 20 | 21 | public TimeInterval Time { get; private set; } 22 | public string FileName { get; set; } 23 | public string Title { get; set; } 24 | public ETrackState State { get; set; } 25 | public Chapter Chapter { get; set; } 26 | public List MetaChapters { get; set; } 27 | 28 | public bool HasMinDuration => Time.Duration >= MIN_DURATION; 29 | 30 | IChapter ITrack.Chapter => Chapter; 31 | ITimeInterval ITrack.Time => Time; 32 | 33 | public Track (TimeSpan duration) { 34 | Time = new TimeInterval (duration); 35 | } 36 | 37 | public Track (TimeSpan begin, TimeSpan end) { 38 | Time = new TimeInterval (begin, end); 39 | } 40 | 41 | public static bool MatchesMinDuration (TimeInterval time) { 42 | if (time is null) 43 | return true; 44 | return time.Duration >= MIN_DURATION; 45 | } 46 | 47 | public override string ToString () { 48 | string chapter = string.Empty; 49 | if (!Chapter.IsNull ()) 50 | chapter = $", Ch: {Chapter}"; 51 | return $"{Time}{chapter}"; 52 | } 53 | } 54 | 55 | } 56 | 57 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/UpdatePackageInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace audiamus.aaxconv.lib { 4 | 5 | public interface IPackageInfo { 6 | string AppName { get; } 7 | Version Version { get; } 8 | bool Preview { get; } 9 | bool DefaultApp { get; } 10 | string Descript { get; } 11 | } 12 | 13 | public class UpdateInteractionMessage { 14 | public EUpdateInteract Kind { get; } 15 | public IPackageInfo PckInfo { get; } 16 | public string RefAppName { get; } 17 | 18 | public UpdateInteractionMessage (EUpdateInteract kind, IPackageInfo pckInfo, string refAppName = null) { 19 | Kind = kind; 20 | PckInfo = pckInfo; 21 | RefAppName = refAppName; 22 | } 23 | } 24 | 25 | public class PackageInfo { 26 | public string Url { get; } 27 | public string AppName { get; } 28 | public string Version { get; } 29 | public bool Preview { get; } 30 | public string Descript { get; } 31 | public string Md5 { get; } 32 | public string InfoLinkUrl { get; } 33 | 34 | //public PackageInfo (string infoLinkUrl) { 35 | // InfoLinkUrl = infoLinkUrl; 36 | //} 37 | 38 | public PackageInfo ( 39 | string url, 40 | string appName, 41 | string version, 42 | bool preview, 43 | string descript, 44 | string md5, 45 | string infoLinkUrl 46 | ) { 47 | Url = url; 48 | AppName = appName; 49 | Version = version; 50 | Preview = preview; 51 | Descript = descript; 52 | Md5 = md5; 53 | InfoLinkUrl = infoLinkUrl; 54 | } 55 | 56 | protected PackageInfo () { } 57 | } 58 | 59 | public class PackageInfoLocal : PackageInfo, IPackageInfo { 60 | public new Version Version { get; } 61 | public string SetupFile { get; set; } 62 | public bool DefaultApp { get; set; } 63 | 64 | public PackageInfoLocal () { } 65 | 66 | public PackageInfoLocal (PackageInfo pi) : base (pi.Url, pi.AppName, pi.Version, pi.Preview, pi.Descript, pi.Md5, pi.InfoLinkUrl) { 67 | Version = tryParse (pi.Version); 68 | } 69 | 70 | private static Version tryParse (string s) { 71 | bool succ = Version.TryParse (s, out Version version); 72 | return succ ? version : null; 73 | } 74 | 75 | } 76 | 77 | 78 | } 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/AaxAudioConverterLib/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/AuxLib/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 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.CodeBase); 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; } = Path.GetDirectoryName(EntryAssembly.Location); 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 TempDirectory { get; } = Path.Combine (LocalApplDirectory, "tmp"); 37 | public static string LogDirectory { get; } = Path.Combine (LocalApplDirectory, "log"); 38 | public static string UserName { get; } = Environment.UserName; 39 | public static string UserDirectoryRoot { get; } = Environment.GetFolderPath (Environment.SpecialFolder.UserProfile); 40 | 41 | private static T getAttribute () where T : Attribute { 42 | object[] attributes = EntryAssembly.GetCustomAttributes (typeof (T), false); 43 | if (attributes.Length == 0) 44 | return null; 45 | return attributes[0] as T; 46 | } 47 | 48 | 49 | private static string getCompanyFileName () { 50 | string company = AssemblyCompany; 51 | if (string.IsNullOrEmpty (company)) 52 | company = "misc"; 53 | if (company.IndexOfAny (INVALID_CHARS) >= 0) 54 | foreach (char c in INVALID_CHARS) 55 | company.Replace (c, ' '); 56 | company = company.Replace (' ', '_'); 57 | return company; 58 | } 59 | 60 | 61 | private static Version getOSVersion () { 62 | const string REGEX = @"\s([0-9.]+)"; 63 | string os = RuntimeInformation.OSDescription; 64 | var regex = new Regex (REGEX); 65 | var match = regex.Match (os); 66 | if (!match.Success) 67 | return new Version (); 68 | string osvers = match.Groups[1].Value; 69 | try { 70 | return new Version (osvers); 71 | } catch (Exception) { 72 | return new Version (); 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/AuxLib/AuxLib.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {64C35BCC-BF7A-47BE-89F2-7ABB470BDB0B} 8 | Library 9 | Properties 10 | audiamus.aux 11 | UtilLib 12 | v4.8 13 | 512 14 | true 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | TRACE;DEBUG 23 | prompt 24 | 4 25 | 7.3 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 7.3 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /src/AuxLib/BigEndianReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace 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/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 audiamus.aux.ex; 8 | 9 | namespace 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 | Trace.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 | Trace.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/ChainPunctuation.cs: -------------------------------------------------------------------------------- 1 | namespace 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/DefaultSettings.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Configuration; 3 | 4 | namespace audiamus.aux { 5 | public class DefaultSettings { 6 | /// 7 | /// Note: ApplicationSettingsBase.Reset () appears not to do this job 8 | /// 9 | /// 10 | static public void ResetToDefault (ApplicationSettingsBase settings) { 11 | foreach (var o in settings.Properties) { 12 | if (o is SettingsProperty prop) { 13 | var val = TypeDescriptor.GetConverter (prop.PropertyType).ConvertFromString (prop.DefaultValue as string); 14 | settings[prop.Name] = val; 15 | } 16 | } 17 | } 18 | 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/AuxLib/Encoding.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 audiamus.aux { 8 | public abstract class Encoding : System.Text.Encoding { 9 | public static System.Text.Encoding Latin1 => System.Text.Encoding.GetEncoding ("ISO-8859-1"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/AuxLib/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 audiamus.aux.ex; 9 | using static audiamus.aux.EnumUtil; 10 | 11 | namespace 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/EnumUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Resources; 5 | using System.Text; 6 | using audiamus.aux.ex; 7 | 8 | namespace 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/IInteractionCallback.cs: -------------------------------------------------------------------------------- 1 | namespace audiamus.aux { 2 | public interface IInteractionCallback { 3 | TResult Interact (T value); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/AuxLib/Indent.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace 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/InteractionCallback.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.Contracts; 3 | using System.Threading; 4 | 5 | namespace 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/InteractionMessage.cs: -------------------------------------------------------------------------------- 1 | namespace audiamus.aux { 2 | public enum ECallbackType { info, infoCancel, warning, error, errorQuestion, errorQuestion3, question, question3, custom} 3 | 4 | public class InteractionMessage { 5 | public ECallbackType Type; 6 | public string Message; 7 | 8 | public InteractionMessage () { } 9 | public InteractionMessage (ECallbackType type, string message) { 10 | Type = type; 11 | Message = message; 12 | } 13 | } 14 | 15 | public class InteractionMessage : InteractionMessage where T: struct, System.Enum { 16 | public T Custom; 17 | } 18 | 19 | public class InteractionMessage2 : InteractionMessage { 20 | public T Custom; 21 | 22 | public InteractionMessage2 (ECallbackType type, string message, T custom) { 23 | Type = type; 24 | Message = message; 25 | Custom = custom; 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/AuxLib/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace audiamus.aux { 9 | public interface IProcessList { 10 | bool Add (Process process); 11 | bool Remove (Process process); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/AuxLib/LocalFileSettingsProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Configuration; 3 | using System.IO; 4 | using static audiamus.aux.ApplEnv; 5 | 6 | namespace audiamus.aux { 7 | /// 8 | /// Customized version of default application settings provider. 9 | /// Maintains a copy of user.config in AppData\Local\[company]\_nohash\[appname]. 10 | /// Takes this copy, if it exists, as input by copying to the hash-name folder, before reading. 11 | /// Copies, after writing, the output from the hash-name folder. 12 | /// Pros: Independent of .exe location and version. 13 | /// Cons: Potential app name and version conflicts. 14 | /// To use: 15 | /// Find Settings.Designer.cs (under Properties | Settings.settings). 16 | /// Decorate "internal sealed partial class Settings" with attribute: 17 | /// [System.Configuration.SettingsProvider (typeof (aux.LocalFileSettingsProvider))] 18 | /// 19 | /// 20 | /// 21 | public class LocalFileSettingsProvider : System.Configuration.LocalFileSettingsProvider { 22 | static readonly string GEN_PATH; 23 | static readonly string SPEC_PATH; 24 | 25 | static readonly char[] INVALID_CHARS = Path.GetInvalidFileNameChars (); 26 | 27 | 28 | static LocalFileSettingsProvider () { 29 | SPEC_PATH = ConfigurationManager.OpenExeConfiguration (ConfigurationUserLevel.PerUserRoamingAndLocal).FilePath; 30 | string dir = LocalCompanyDirectory; 31 | dir = Path.Combine (dir, "_nohash", ApplName); 32 | var path = Path.Combine (dir, Path.GetFileName (SPEC_PATH)); 33 | GEN_PATH = path; 34 | } 35 | 36 | public override SettingsPropertyValueCollection GetPropertyValues (SettingsContext context, SettingsPropertyCollection properties) { 37 | try { 38 | if (File.Exists (GEN_PATH)) { 39 | Directory.CreateDirectory (Path.GetDirectoryName (SPEC_PATH)); 40 | File.Copy (GEN_PATH, SPEC_PATH, true); 41 | } 42 | } catch (Exception) { 43 | } 44 | return base.GetPropertyValues (context, properties); 45 | } 46 | 47 | public override void SetPropertyValues (SettingsContext context, SettingsPropertyValueCollection values) { 48 | base.SetPropertyValues (context, values); 49 | try { 50 | if (File.Exists (SPEC_PATH)) { 51 | Directory.CreateDirectory (Path.GetDirectoryName (GEN_PATH)); 52 | File.Copy (SPEC_PATH, GEN_PATH, true); 53 | } 54 | } catch (Exception) { 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/AuxLib/ProcessHost.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Text; 5 | 6 | namespace 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 | Singleton.Instance.Add (p); 53 | Process = p; 54 | 55 | if (async) { 56 | if (getStdErrorNotOutput) 57 | p.BeginErrorReadLine (); 58 | else 59 | p.BeginOutputReadLine (); 60 | } 61 | p.WaitForExit (); 62 | 63 | Singleton.Instance.Remove (p); 64 | Process = null; 65 | 66 | if (!async) { 67 | if (getStdErrorNotOutput) 68 | result = p.StandardError.ReadToEnd (); 69 | else 70 | result = p.StandardOutput.ReadToEnd (); 71 | } else { 72 | if (processOutputStringBuilder.Length > 0) 73 | result = processOutputStringBuilder.ToString (); 74 | } 75 | 76 | } 77 | 78 | return result; 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/AuxLib/ProcessList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | 5 | namespace 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/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("AuxLib")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("audiamus")] 12 | [assembly: AssemblyProduct("AuxLib")] 13 | [assembly: AssemblyCopyright("Copyright © 2019 - 2023 audiamus")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("64c35bcc-bf7a-47be-89f2-7abb470bdb0b")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.9.0.0")] 36 | [assembly: AssemblyFileVersion("1.9.0.0")] 37 | -------------------------------------------------------------------------------- /src/AuxLib/ResourceGuard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace 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/ResourceManagerEx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Resources; 3 | 4 | namespace 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/Singleton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace 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/Temp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace 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/AuxWin32Lib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("auxWin32Lib")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("audiamus")] 12 | [assembly: AssemblyProduct("auxWin32Lib")] 13 | [assembly: AssemblyCopyright("Copyright © 2019 - 2023 audiamus")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("66af7db4-aa8e-45f5-bb1b-919c5008e6b0")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.3.0.0")] 36 | [assembly: AssemblyFileVersion("1.3.0.0")] 37 | -------------------------------------------------------------------------------- /src/AuxWin32Lib/auxWin32Lib.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {66AF7DB4-AA8E-45F5-BB1B-919C5008E6B0} 8 | Library 9 | Properties 10 | audiamus.aux.w32 11 | AuxWin32Lib 12 | v4.8 13 | 512 14 | true 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | true 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/AuxWinLib/AuxWinLib.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {D3ED00A5-5855-40F4-AEB8-BB9EEF35B7F7} 8 | Library 9 | Properties 10 | audiamus.aux.win 11 | AuxLib 12 | v4.8 13 | 512 14 | true 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 7.3 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 7.3 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Component 59 | 60 | 61 | 62 | 63 | {64c35bcc-bf7a-47be-89f2-7abb470bdb0b} 64 | AuxLib 65 | 66 | 67 | {d8e74eae-8661-4764-baef-e9e138779d85} 68 | AuxWin.DialogBox 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/AuxWinLib/ComboBoxEnumAdapter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Resources; 4 | using System.Windows.Forms; 5 | 6 | namespace audiamus.aux.win { 7 | public class ComboBoxEnumAdapter : EnumConverter where TEnum : struct, Enum { 8 | private readonly ComboBox _comboBox; 9 | 10 | public TEnum Value => getValue (); 11 | 12 | public ComboBoxEnumAdapter (ComboBox comboBox, ResourceManager resmgr, TEnum value) { 13 | _comboBox = comboBox; 14 | base.ResourceManager = resmgr; 15 | var stringValues = Values.Select (v => ConvertTo (v, typeof (string))).ToArray (); 16 | comboBox.Items.Clear (); 17 | comboBox.Items.AddRange (stringValues); 18 | 19 | int idx = Values.IndexOf (value); 20 | comboBox.SelectedIndex = idx; 21 | } 22 | 23 | 24 | private TEnum getValue () { 25 | int idx = _comboBox.SelectedIndex; 26 | if (idx < 0) 27 | return default; 28 | return Values.ElementAt (idx); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/AuxWinLib/ControlExPathEllipsis.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Windows.Forms; 3 | 4 | namespace audiamus.aux.win.ex { 5 | public static class ControlExPathEllipsis { 6 | public static void SetTextAsPathWithEllipsis (this Control label, string text = null) { 7 | if (text is null) 8 | text = (string)label.Tag; 9 | else 10 | label.Tag = text; 11 | string text2 = string.Copy (text); 12 | Size size = new Size (label.Width - 8, label.Height); 13 | TextRenderer.MeasureText (text2, label.Font, 14 | size, TextFormatFlags.ModifyString | TextFormatFlags.PathEllipsis); 15 | int pos = text2.IndexOf ('\0'); 16 | if (pos >= 0) 17 | text2 = text2.Substring (0, pos); 18 | label.Text = text2; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/AuxWinLib/DialogBox/AssemblyInfo.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/src/AuxWinLib/DialogBox/AssemblyInfo.cs -------------------------------------------------------------------------------- /src/AuxWinLib/DialogBox/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 | // https://www.codeproject.com/Articles/9984/Centering-MessageBox-Common-DialogBox-or-Form-on-a 17 | // 18 | //----------------------------------------------------------------------------- 19 | using System; 20 | using System.Text; 21 | using System.Drawing; 22 | using System.Windows.Forms; 23 | using System.Runtime.InteropServices; 24 | 25 | namespace audiamus.aux.win.Win32API 26 | { 27 | /////////////////////////////////////////////////////////////////////// 28 | #region Generic declarations 29 | 30 | /// 31 | /// Rectangle parameters exposed as a structure. 32 | /// 33 | public struct RECT 34 | { 35 | /// 36 | /// Rectangle members. 37 | /// 38 | public int left, top, right, bottom; 39 | } 40 | 41 | #endregion 42 | 43 | /////////////////////////////////////////////////////////////////////// 44 | #region Util class 45 | 46 | /// 47 | /// Utility functions. 48 | /// 49 | public sealed class API 50 | { 51 | private API() {} // To remove the constructor from the documentation! 52 | 53 | /// 54 | /// Get true multiscreen size. 55 | /// 56 | public static Rectangle TrueScreenRect 57 | { 58 | get 59 | { 60 | // get the biggest screen area 61 | Rectangle rectScreen = Screen.PrimaryScreen.WorkingArea; 62 | int left = rectScreen.Left; 63 | int top = rectScreen.Top; 64 | int right = rectScreen.Right; 65 | int bottom = rectScreen.Bottom; 66 | foreach (Screen screen in Screen.AllScreens) 67 | { 68 | left = Math.Min(left, screen.WorkingArea.Left); 69 | right = Math.Max(right, screen.WorkingArea.Right); 70 | top = Math.Min(top, screen.WorkingArea.Top); 71 | bottom = Math.Max(bottom, screen.WorkingArea.Bottom); 72 | } 73 | return new Rectangle(left, top, right-left, bottom-top); 74 | } 75 | } 76 | } 77 | 78 | #endregion 79 | 80 | /////////////////////////////////////////////////////////////////////// 81 | #region USER32 class 82 | 83 | /// 84 | /// Class to expose USER32 API functions. 85 | /// 86 | public sealed class USER32 87 | { 88 | private USER32() {} // To remove the constructor from the documentation! 89 | 90 | [DllImport("user32", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 91 | internal static extern int GetWindowRect(IntPtr hWnd, ref RECT rect); 92 | 93 | [DllImport("user32", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 94 | internal static extern int MoveWindow(IntPtr hWnd, int x, int y, int w, int h, int repaint); 95 | 96 | [DllImport("user32", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 97 | internal static extern IntPtr GetActiveWindow(); 98 | 99 | [DllImport("user32", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 100 | internal static extern int GetClassName(IntPtr hwnd, StringBuilder lpClassName, int nMaxCount); 101 | } 102 | #endregion 103 | } 104 | -------------------------------------------------------------------------------- /src/AuxWinLib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("AuxWinLib")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("audiamus")] 12 | [assembly: AssemblyProduct("AuxWinLib")] 13 | [assembly: AssemblyCopyright("Copyright © 2019 - 2023 audiamus")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("d3ed00a5-5855-40f4-aeb8-bb9eef35b7f7")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.5.0.0")] 36 | [assembly: AssemblyFileVersion("1.5.0.0")] 37 | -------------------------------------------------------------------------------- /src/AuxWinLib/RtfBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace audiamus.aux.win { 4 | public class RtfBuilder { 5 | StringBuilder _builder = new StringBuilder (); 6 | 7 | public void AppendBold (string text) { 8 | _builder.Append (@"{\b "); 9 | _builder.Append (text); 10 | _builder.Append (@"}"); 11 | } 12 | 13 | public void AppendItalic (string text) { 14 | _builder.Append (@"{\i "); 15 | _builder.Append (text); 16 | _builder.Append (@"}"); 17 | } 18 | 19 | public void Append (string text) { 20 | _builder.Append (text); 21 | } 22 | 23 | public void AppendLine () { 24 | _builder.Append (@"\line "); 25 | } 26 | 27 | public void AppendPara () { 28 | _builder.Append (@"\par "); 29 | } 30 | 31 | public string ToRtf () { 32 | return @"{\rtf1\ansi " + _builder.ToString () + @" }"; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/AuxWinLib/VerticalProgressBar.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | 3 | namespace audiamus.aux.win { 4 | public class VerticalProgressBar : ProgressBar { 5 | 6 | const int PBS_VERTICAL = 0x04; 7 | 8 | protected override CreateParams CreateParams { 9 | get 10 | { 11 | CreateParams cp = base.CreateParams; 12 | cp.Style |= PBS_VERTICAL; 13 | return cp; 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/InnoSetup/AaxAudioConverter setup.iss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiamus/AaxAudioConverter/c34780299f9b2975bf8a6b8c511a6e2e5a42b37e/src/InnoSetup/AaxAudioConverter setup.iss -------------------------------------------------------------------------------- /src/PerfLib/CpuUsage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using static audiamus.perf.ProcessCpuCounter; 4 | 5 | namespace audiamus.perf { 6 | public class CpuUsage { 7 | private const float SAMPLE_FREQUENCY_MILLIS = 200; //1000; 8 | 9 | public const string PROCESSOR = "Processor"; 10 | public const string TOTAL = "_Total"; 11 | 12 | private readonly object _lockable = new object (); 13 | private PerformanceCounter _counter; 14 | private float? _lastSample; 15 | private DateTime _lastSampleTime; 16 | 17 | public CpuUsage (int pid = 0) { 18 | try { 19 | if (pid == 0) 20 | this._counter = new PerformanceCounter (PROCESSOR, PROCESSOR_TIME, TOTAL, true); 21 | else 22 | this._counter = GetPerfCounterForProcessId (pid); 23 | 24 | _counter?.NextValue (); 25 | } catch (Exception) { } 26 | } 27 | 28 | public float? GetCurrentValue () { 29 | if (_counter is null) 30 | return null; 31 | if ((DateTime.UtcNow - _lastSampleTime).TotalMilliseconds > SAMPLE_FREQUENCY_MILLIS) { 32 | lock (_lockable) { 33 | if ((DateTime.UtcNow - _lastSampleTime).TotalMilliseconds > SAMPLE_FREQUENCY_MILLIS) { 34 | try { 35 | _lastSample = _counter.NextValue (); 36 | } catch (Exception) { 37 | _lastSample = null; 38 | } 39 | _lastSampleTime = DateTime.UtcNow; 40 | } 41 | } 42 | } 43 | 44 | return _lastSample; 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/PerfLib/PerfCallback.cs: -------------------------------------------------------------------------------- 1 | namespace audiamus.perf { 2 | public interface IValueMax { 3 | int Value { get; } 4 | int Max { get; } 5 | } 6 | 7 | public interface IPerfCallback { 8 | IValueMax Processes { get; } 9 | IValueMax LoadPercent { get; } 10 | } 11 | 12 | public class PerfCallback : IPerfCallback { 13 | public class ValueMax : IValueMax { 14 | public int Value { get; } 15 | public int Max { get; } 16 | 17 | public ValueMax (int val, int max = 100) { 18 | Value = val; 19 | Max = max; 20 | } 21 | } 22 | 23 | public IValueMax Processes { get; } 24 | public IValueMax LoadPercent { get; } 25 | 26 | public PerfCallback (IValueMax processes, IValueMax loadPercent) { 27 | Processes = processes; 28 | LoadPercent = loadPercent; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/PerfLib/PerfLib.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {AB642D01-29BF-4FBC-A001-E1795AC38108} 8 | Library 9 | Properties 10 | audiamus.perf 11 | PerfLib 12 | v4.8 13 | 512 14 | true 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | {64C35BCC-BF7A-47BE-89F2-7ABB470BDB0B} 54 | AuxLib 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/PerfLib/PerformanceMonitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Threading; 6 | using audiamus.aux; 7 | using audiamus.aux.ex; 8 | 9 | namespace audiamus.perf { 10 | public class PerformanceMonitor : IProcessList, IDisposable { 11 | 12 | const int IVL_MS = 200; 13 | 14 | struct ProcessCpuUsage { 15 | public Process Process { get; } 16 | public CpuUsage Usage { get; } 17 | 18 | public ProcessCpuUsage (Process process) { 19 | Process = process; 20 | Usage = new CpuUsage (process.Id); 21 | } 22 | } 23 | 24 | public Action Callback { 25 | private get => _callback; 26 | set 27 | { 28 | lock (_lockable) 29 | _callback = value; 30 | } 31 | } 32 | 33 | private Dictionary _processes = 34 | new Dictionary (); 35 | 36 | private readonly object _lockable = new object (); 37 | private readonly int _parentPID; 38 | private readonly string _childProcessName; 39 | private Timer _timer; 40 | private Action _callback; 41 | private float _meanUsage; 42 | 43 | public PerformanceMonitor (string childProcessName = null) { 44 | var process = Process.GetCurrentProcess (); 45 | _parentPID = process.Id; 46 | (this as IProcessList).Add (process); 47 | 48 | _childProcessName = childProcessName; 49 | 50 | Singleton.Instance.Notify = this; 51 | } 52 | 53 | public void Dispose () { 54 | Stop (); 55 | } 56 | 57 | public void Start () { 58 | if (_timer != null) 59 | return; 60 | _timer = new Timer (timerCallback, null, IVL_MS, IVL_MS); 61 | } 62 | 63 | 64 | public void Stop () { 65 | _timer?.Dispose (); 66 | _timer = null; 67 | _meanUsage = 0; 68 | 69 | lock (_lockable) { 70 | var processes = _processes.Keys.ToList (); 71 | processes.Remove (_parentPID); 72 | foreach (var p in processes) 73 | _processes.Remove (p); 74 | } 75 | 76 | Callback?.Invoke (new PerfCallback ( 77 | new PerfCallback.ValueMax (0, ApplEnv.ProcessorCount), 78 | new PerfCallback.ValueMax (0) 79 | )); 80 | 81 | } 82 | 83 | private void timerCallback (object state) { 84 | IEnumerable processList; 85 | lock (_lockable) { 86 | if (Callback is null) 87 | return; 88 | processList = _processes.Values.ToList (); 89 | } 90 | 91 | float usage = 0; 92 | int cnt = 0; 93 | 94 | foreach (var proc in processList) { 95 | float? usg = proc.GetCurrentValue (); 96 | if (usg.HasValue) { 97 | if (usg.Value > 0) 98 | cnt++; 99 | usage += usg.Value; 100 | } 101 | } 102 | 103 | if (cnt > 0) 104 | usage /= cnt; 105 | usage = Math.Min (usage, 100f); 106 | 107 | const int F = 3; 108 | if (_meanUsage < 0) 109 | _meanUsage = (int)usage; 110 | else 111 | _meanUsage = ((_meanUsage * F) + (int)usage) / (F + 1); 112 | 113 | Callback?.Invoke (new PerfCallback ( 114 | new PerfCallback.ValueMax (processList.Count() - 1, ApplEnv.ProcessorCount), 115 | new PerfCallback.ValueMax ((int)_meanUsage) 116 | )); 117 | 118 | } 119 | 120 | bool IProcessList.Add (Process process) { 121 | if (!_childProcessName.IsNullOrWhiteSpace () && !process.ProcessName.StartsWith (_childProcessName, StringComparison.InvariantCultureIgnoreCase)) 122 | return false; 123 | lock (_lockable) { 124 | _processes[process.Id] = new CpuUsage (process.Id); 125 | Logging.Log (4, this, () => $"pid={process.Id}, #proc={_processes.Count}"); 126 | } 127 | return true; 128 | } 129 | 130 | bool IProcessList.Remove (Process process) { 131 | lock (_lockable) { 132 | bool succ = _processes.Remove (process.Id); 133 | Logging.Log (4, this, () => $"pid={process.Id}, succ={succ}, #proc={_processes.Count}"); 134 | return succ; 135 | } 136 | } 137 | 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/PerfLib/ProcessCpuCounter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace audiamus.perf { 7 | public class ProcessCpuCounter { 8 | public const string PROCESSOR_TIME = "% Processor Time"; 9 | public const string PROCESS = "Process"; 10 | public const string ID_PROCESS = "ID Process"; 11 | 12 | public static PerformanceCounter GetPerfCounterForProcessId (int processId, string processCounterName = PROCESSOR_TIME) { 13 | string instance = GetInstanceNameForProcessId (processId); 14 | if (string.IsNullOrEmpty (instance)) 15 | return null; 16 | 17 | return new PerformanceCounter (PROCESS, processCounterName, instance); 18 | } 19 | 20 | public static string GetInstanceNameForProcessId (int processId) { 21 | try { 22 | var process = Process.GetProcessById (processId); 23 | string processName = Path.GetFileNameWithoutExtension (process.ProcessName); 24 | 25 | PerformanceCounterCategory cat = new PerformanceCounterCategory (PROCESS); 26 | string[] instances = cat.GetInstanceNames () 27 | .Where (inst => inst.StartsWith (processName)) 28 | .ToArray (); 29 | 30 | foreach (string instance in instances) { 31 | using (PerformanceCounter cnt = new PerformanceCounter (PROCESS, ID_PROCESS, instance, true)) { 32 | int val = (int)cnt.RawValue; 33 | if (val == processId) 34 | return instance; 35 | } 36 | } 37 | } catch (Exception) { } 38 | return null; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/PerfLib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("PerfLib")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("audiamus")] 12 | [assembly: AssemblyProduct("PerfLib")] 13 | [assembly: AssemblyCopyright("Copyright © 2021 - 2023 audiamus")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("ab642d01-29bf-4fbc-a001-e1795ac38108")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.2.0.0")] 36 | [assembly: AssemblyFileVersion("1.2.0.0")] 37 | -------------------------------------------------------------------------------- /src/PropGridLib/Attributes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace 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/BasePropertyGridAdapter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Reflection; 4 | 5 | namespace audiamus.aux.propgrid { 6 | public enum EReadonly { none, minimum, search, modify, modifyExt, all }; 7 | public enum EVisibility { none, minmum, search, all }; 8 | 9 | /// 10 | /// Abstract base class tailored as a PropertyGrid subject. 11 | /// Supports property ordering and dynamic readonly and visibility flags 12 | /// for individual properties. 13 | /// Adds simple DataSource property for external representation of the data to 14 | /// become the PropertyGrid subject ("SelectedObject"). 15 | /// 16 | /// Type of external data representation. 17 | [TypeConverter (typeof (PropertySorter))] 18 | public abstract class BasePropertyGridAdapter : DynamicTypeDescriptor { 19 | 20 | #region private fields 21 | bool _isReadOnly; 22 | Action _refreshDelegate; 23 | 24 | readonly T _datasource; 25 | 26 | #endregion fields 27 | #region properties 28 | 29 | [Browsable (false)] 30 | public virtual T DataSource { 31 | get 32 | { 33 | return _datasource; 34 | } 35 | } 36 | 37 | [Browsable (false)] 38 | public Action RefreshDelegate 39 | { 40 | protected get 41 | { 42 | return _refreshDelegate; 43 | } 44 | set 45 | { 46 | if (RefreshDelegate == value) 47 | return; 48 | _refreshDelegate = value; 49 | RefreshDelegate?.Invoke(); 50 | } 51 | } 52 | #endregion properties 53 | #region ctor 54 | 55 | protected BasePropertyGridAdapter (T datasource) { 56 | this._datasource = datasource; 57 | 58 | Type t = GetType (); 59 | 60 | MemberInfo [] memberinfos = t.FindMembers 61 | (MemberTypes.Property, 62 | BindingFlags.Public | BindingFlags.Instance, // | BindingFlags.DeclaredOnly, 63 | new MemberFilter(delegateToSearchCriteria), 64 | null); 65 | 66 | foreach (MemberInfo mi in memberinfos) { 67 | PropertyInfo pi = mi as PropertyInfo; 68 | if (pi == null) 69 | continue; 70 | 71 | string name = pi.Name; 72 | if (!PropertyCommands.Contains (name)) { 73 | PropertyCommands.Add (new 74 | PropertyCommand (name, true, false)); 75 | } 76 | } 77 | } 78 | 79 | #endregion ctor 80 | #region private static methods 81 | static bool delegateToSearchCriteria (MemberInfo objMemberInfo, Object objSearch) { 82 | PropertyInfo pi = objMemberInfo as PropertyInfo; 83 | if (pi == null) 84 | return false; 85 | 86 | object[] aAttributes = pi.GetCustomAttributes (typeof (BrowsableAttribute), false); 87 | 88 | bool c = true; 89 | if (aAttributes != null && aAttributes.Length > 0) { 90 | BrowsableAttribute ba = aAttributes[0] as BrowsableAttribute; 91 | if (ba != null) 92 | c = ba.Browsable; 93 | } 94 | 95 | return c; 96 | } 97 | 98 | 99 | #endregion static methods 100 | #region public virtual methods 101 | 102 | public virtual void SetReadonly (EReadonly modifier) { 103 | if (!readOnlyChange (modifier)) 104 | return; 105 | bool ro = modifier == EReadonly.all; 106 | _isReadOnly = ro; 107 | foreach (PropertyCommand pc in PropertyCommands) { 108 | pc.ReadOnly = ro; 109 | } 110 | } 111 | 112 | 113 | public virtual void SetVisible (EVisibility modifier) { 114 | bool vis = modifier == EVisibility.all; 115 | foreach (PropertyCommand pc in PropertyCommands) { 116 | pc.Visible = vis; 117 | } 118 | } 119 | 120 | #endregion 121 | #region protected methods 122 | protected bool readOnlyChange (EReadonly modifier) { 123 | return modifier == EReadonly.all && !_isReadOnly || modifier == EReadonly.none && _isReadOnly; 124 | } 125 | #endregion 126 | } 127 | 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/PropGridLib/PropGridLib.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {7B091DC6-75AA-403C-AD5E-EA3CB6610CD0} 8 | Library 9 | Properties 10 | audiamus.aux.propgrid 11 | PropGridLib 12 | v4.8 13 | 512 14 | true 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/PropGridLib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("PropGridLib")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("audiamus")] 12 | [assembly: AssemblyProduct("PropGridLib")] 13 | [assembly: AssemblyCopyright("Copyright © 2019 - 2023 audiamus")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("7b091dc6-75aa-403c-ad5e-ea3cb6610cd0")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.2.0.0")] 36 | [assembly: AssemblyFileVersion("1.2.0.0")] 37 | -------------------------------------------------------------------------------- /src/PropGridLib/PropertySorter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.ComponentModel; 4 | 5 | namespace 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/TreeDecomposition/CustomAttributes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace 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/Enums.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | namespace 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/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace 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/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("TreeDecomposition")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("audiamus")] 12 | [assembly: AssemblyProduct("TreeDecomposition")] 13 | [assembly: AssemblyCopyright("Copyright © 2020 - 2023 audiamus")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("bbefb463-1f6c-4d35-af83-b5c3cea9915e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.2.0.0")] 36 | [assembly: AssemblyFileVersion("1.2.0.0")] 37 | -------------------------------------------------------------------------------- /src/TreeDecomposition/ToStringConverter.cs: -------------------------------------------------------------------------------- 1 | namespace audiamus.aux.diagn { 2 | public abstract class ToStringConverter { 3 | public abstract string ToString (object o, string format = null); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/TreeDecomposition/TreeDecomposition.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {BBEFB463-1F6C-4D35-AF83-B5C3CEA9915E} 8 | Library 9 | Properties 10 | audiamus.aux.diagn 11 | TreeDecomposition 12 | v4.8 13 | 512 14 | true 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 7.1 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 7.1 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {64c35bcc-bf7a-47be-89f2-7abb470bdb0b} 60 | AuxLib 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/TreeDecomposition/TreeDecompositionExtension.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | 4 | namespace 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/TypeExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace 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 | --------------------------------------------------------------------------------