diff --git a/Readme.md b/Readme.md index 7d5b60c..004e954 100644 --- a/Readme.md +++ b/Readme.md @@ -12,7 +12,7 @@ This is a plugin for [Winamp](http://www.winamp.com/) that saves text informatio - [Installation](#installation) - [Configuration](#configuration) - [Text](#text) - - [Metadata fields](#metadata-fields) + - [Placeholder fields](#placeholder-fields) - [Helpers](#helpers) - [Formatting](#formatting) - [Album art](#album-art) @@ -70,7 +70,7 @@ U2 – Exit – The Joshua Tree To customize the text file location and contents, go to the plugin preferences in Winamp. -1. You can change the file contents by editing the **Text template** and inserting placeholders inside `{{` `}}`, either with the **Insert** button or by typing them manually. See [Metadata fields](#metadata-fields) below for all the fields you can use in a placeholder. For example, a simple template that could render the above example text is +1. You can change the file contents by editing the **Text template** and inserting placeholders inside `{{` `}}`, either with the **Insert** button or by typing them manually. See [Placeholder fields](#placeholder-fields) below for all the fields you can use in a placeholder. For example, a simple template that could render the above example text is ```handlebars {{Artist}} – {{Title}} – {{Album}} ``` @@ -79,9 +79,9 @@ To customize the text file location and contents, go to the plugin preferences i When Winamp is not playing a song, this text file will be truncated to 0 bytes. -#### Metadata fields +#### Placeholder fields -Metadata values that are missing or empty will be rendered as the empty string. +Placeholder values that are missing or empty will be rendered as the empty string. |Field name|Type|Examples|Notes| |-|-|-|-| @@ -96,6 +96,7 @@ Metadata values that are missing or empty will be rendered as the empty string. |`Conductor`|string||| |`Director`|string||Most commonly used for video files| |`Disc`|int|`1`|If it can't be parsed as an int (like `1/2`) it will be a string| +|`Elapsed`|TimeSpan|`00:00:28.5080000`|Updated 1hz, millisecond resolution. See [formatting](#formatting) for `m:ss` and other formats.| |`Family`|string|`MPEG Layer 3 Audio File`|Codec or container format| |`FileBasename`|string|`Exit.mp3`|Filename without path| |`FileBasenameWithoutExtension`|string|`Exit`|Filename without path or extension| @@ -124,11 +125,11 @@ Metadata values that are missing or empty will be rendered as the empty string. |`VBR`|bool|`false`|`true` for variable bitrate, `false` for constant bitrate| |`Year`|int|`1987`|If it can't be parsed as an int (like `1987-01-01`) it will be a string| -Any other values you use in a placeholder will be requested directly from Winamp, and the response will be output as-is. If you can find other fields that Winamp handles for audio files, please [file an enhancement issue](https://github.com/Aldaviva/WinampNowPlayingToFile/issues/new?labels=enhancement&title=New%20metadata%20field:%20) so it can be added to this program and documentation. +Any other values you use in a placeholder will be requested directly from Winamp as file metadata, and the response will be output as-is. If you can find other fields that Winamp handles for audio files, please [file an enhancement issue](https://github.com/Aldaviva/WinampNowPlayingToFile/issues/new?labels=enhancement&title=New%20metadata%20field:%20) so it can be added to this program and documentation. #### Helpers -Template logic can be added using [Handlebars expressions](https://handlebarsjs.com/), including the [built-in helpers](https://handlebarsjs.com/guide/builtin-helpers.html) like `{{#if expr}}`, `{{#elif expr}}`, `{{#else}}`, and `{{/if}}`. To output a line break (CRLF), use `{{#newline}}`. +Template logic can be added using [Handlebars expressions](https://github.com/jehugaleahsa/mustache-sharp/blob/v1.0/README.md), including the [built-in helpers](https://github.com/jehugaleahsa/mustache-sharp/blob/v1.0/README.md#placeholders) like `{{#if expr}}`, `{{#elif expr}}`, `{{#else}}`, and `{{/if}}`. To output a line break (CRLF), use `{{#newline}}`. For example, you can conditionally include artist and album only if those fields exist on your song and are nonempty. ```handlebars diff --git a/Test/Business/NowPlayingToFileManagerTest.cs b/Test/Business/NowPlayingToFileManagerTest.cs index a7cc51d..405de69 100644 --- a/Test/Business/NowPlayingToFileManagerTest.cs +++ b/Test/Business/NowPlayingToFileManagerTest.cs @@ -1,10 +1,11 @@ -using System; +using Daniel15.Sharpamp; +using FakeItEasy; +using FluentAssertions; +using System; using System.Collections.Generic; using System.IO; using System.Text; -using Daniel15.Sharpamp; -using FakeItEasy; -using FluentAssertions; +using System.Threading; using WinampNowPlayingToFile.Business; using WinampNowPlayingToFile.Facade; using WinampNowPlayingToFile.Settings; @@ -51,6 +52,7 @@ private static void onManagerError(object _, NowPlayingException exception) { public void Dispose() { cleanUp(); + manager.renderTextTimer.Stop(); } private void cleanUp() { @@ -338,4 +340,21 @@ public void queryCustomMetadataFieldFromWinamp() { A.CallTo(() => winampController.fetchMetadataFieldValue("CustomField")).MustHaveHappenedOnceExactly(); } + [Fact] + public void elapsedTriggersPeriodicRenders() { + CountdownEvent latch = new(5); + + manager.renderTextTimer.Interval = 100; + A.CallTo(() => winampController.fetchMetadataFieldValue("Elapsed")).ReturnsLazily(() => { + latch.Signal(); + return TimeSpan.FromSeconds(1); + }); + + A.CallTo(() => settings.textTemplate).Returns("{{Elapsed:m\\:ss}}"); + settings.settingsUpdated += Raise.WithEmpty(); + + latch.Wait(10_000); + A.CallTo(() => winampController.fetchMetadataFieldValue("Elapsed")).MustHaveHappenedANumberOfTimesMatching(i => i >= latch.InitialCount); + } + } \ No newline at end of file diff --git a/Test/Test.csproj b/Test/Test.csproj index d05e1e3..1135bcd 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -11,12 +11,12 @@ - + - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/WinampNowPlayingToFile/Business/NowPlayingToFileManager.cs b/WinampNowPlayingToFile/Business/NowPlayingToFileManager.cs index 49ecd2b..658da89 100644 --- a/WinampNowPlayingToFile/Business/NowPlayingToFileManager.cs +++ b/WinampNowPlayingToFile/Business/NowPlayingToFileManager.cs @@ -1,12 +1,13 @@ #nullable enable +using Daniel15.Sharpamp; +using Mustache; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; -using Daniel15.Sharpamp; -using Mustache; +using System.Timers; using WinampNowPlayingToFile.Facade; using WinampNowPlayingToFile.Settings; using Song = WinampNowPlayingToFile.Facade.Song; @@ -23,7 +24,6 @@ public interface INowPlayingToFileManager { public class NowPlayingToFileManager: INowPlayingToFileManager { - private static readonly FormatCompiler TEMPLATE_COMPILER = new(); private static readonly UTF8Encoding UTF8 = new(false, true); private static readonly IEnumerable ARTWORK_EXTENSIONS = new[] { ".bmp", ".gif", ".jpeg", ".jpg", ".png" }; private static readonly IEnumerable ARTWORK_BASE_NAMES = new[] { "cover", "folder", "front", "albumart" }; @@ -31,10 +31,23 @@ public class NowPlayingToFileManager: INowPlayingToFileManager { private static byte[]? albumArtWhenMissingFromSong => getInstallationDirectoryImageOrFallback("emptyAlbumArt.png"); private static byte[]? albumArtWhenStopped => getInstallationDirectoryImageOrFallback("stoppedAlbumArt.png"); - private readonly WinampController winampController; - private readonly ISettings settings; + private readonly WinampController winampController; + private readonly ISettings settings; + private readonly FormatCompiler templateCompiler = new(); + internal readonly Timer renderTextTimer = new(1000); private Generator? cachedTemplate; + private bool _textTemplateDependsOnTime; + + private bool textTemplateDependsOnTime { + get => _textTemplateDependsOnTime; + set { + if (_textTemplateDependsOnTime != value) { + _textTemplateDependsOnTime = value; + startOrStopTextRenderingTimer(); + } + } + } public event EventHandler? error; @@ -42,21 +55,38 @@ public NowPlayingToFileManager(ISettings settings, WinampController winampContro this.winampController = winampController; this.settings = settings; - this.winampController.songChanged += delegate { update(); }; - this.winampController.statusChanged += delegate { update(); }; + this.winampController.songChanged += delegate { update(); }; + + this.winampController.statusChanged += (_, args) => { + update(); + startOrStopTextRenderingTimer(args.Status); + }; + this.settings.settingsUpdated += delegate { - cachedTemplate = null; + cachedTemplate = null; + textTemplateDependsOnTime = false; update(); }; + templateCompiler.PlaceholderFound += (_, args) => { + if (args.Key.Equals("Elapsed", StringComparison.CurrentCultureIgnoreCase)) { + textTemplateDependsOnTime = true; + } + }; + + renderTextTimer.Elapsed += (_, _) => { update(false); }; + update(); } - internal void update() { + internal void update(bool updateAlbumArt = true) { try { if (winampController.currentSong is { Filename: not "" } currentSong) { saveText(renderText(currentSong)); - saveImage(findAlbumArt(currentSong)); + + if (updateAlbumArt) { + saveImage(findAlbumArt(currentSong)); + } } } catch (Exception e) when (e is not OutOfMemoryException) { error?.Invoke(this, new NowPlayingException("Exception while updating song", e, winampController.currentSong)); @@ -73,7 +103,7 @@ private void saveText(string nowPlayingText) { private Generator getTemplate() { if (cachedTemplate == null) { - cachedTemplate = TEMPLATE_COMPILER.Compile(settings.textTemplate); + cachedTemplate = templateCompiler.Compile(settings.textTemplate); cachedTemplate.KeyNotFound += fetchExtraMetadata; } @@ -174,7 +204,13 @@ private void saveImage(byte[]? imageData) { } } + private void startOrStopTextRenderingTimer(Status? playbackStatus = null) { + playbackStatus ??= winampController.status; + renderTextTimer.Enabled = playbackStatus == Status.Playing && textTemplateDependsOnTime; + } + public virtual void onQuit() { + renderTextTimer.Stop(); saveText(string.Empty); saveImage(albumArtWhenStopped); } diff --git a/WinampNowPlayingToFile/Facade/WinampControllerImpl.cs b/WinampNowPlayingToFile/Facade/WinampControllerImpl.cs index adbe9b2..3eb20fb 100644 --- a/WinampNowPlayingToFile/Facade/WinampControllerImpl.cs +++ b/WinampNowPlayingToFile/Facade/WinampControllerImpl.cs @@ -1,9 +1,9 @@ #nullable enable +using Daniel15.Sharpamp; using System; using System.IO; using System.Reflection; -using Daniel15.Sharpamp; namespace WinampNowPlayingToFile.Facade; @@ -26,7 +26,10 @@ public interface WinampController { public class WinampControllerImpl: WinampController { - private readonly Winamp winamp; + private readonly Winamp winamp; + + // ReSharper disable once InconsistentNaming - this is how the method is named in Sharpamp + private readonly Func sendIPCCommandInt; private readonly Func getMetadata; public event SongChangedEventHandler? songChanged; @@ -40,6 +43,12 @@ public WinampControllerImpl(Winamp winamp) { getMetadata = (Func) winamp.GetType() .GetMethod("GetMetadata", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(string), typeof(string) }, null)! .CreateDelegate(typeof(Func), winamp); + + Type ipcCommand = winamp.GetType().GetNestedType("IPCCommand", BindingFlags.NonPublic); + + sendIPCCommandInt = (Func) winamp.GetType() + .GetMethod("SendIPCCommandInt", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { ipcCommand }, null)! + .CreateDelegate(typeof(Func), winamp); } public Status status => winamp.Status; @@ -71,10 +80,13 @@ public object fetchMetadataFieldValue(string metadataFieldName) { string songFilename = winamp.CurrentSong.Filename; try { - if (metadataFieldName == "filebasename") { - return Path.GetFileName(songFilename); - } else if (metadataFieldName == "filebasenamewithoutextension") { - return Path.GetFileNameWithoutExtension(songFilename); + switch (metadataFieldName) { + case "filebasename": + return Path.GetFileName(songFilename); + case "filebasenamewithoutextension": + return Path.GetFileNameWithoutExtension(songFilename); + case "elapsed": + return TimeSpan.FromMilliseconds(sendIPCCommandInt(105)); } } catch (ArgumentException) { return string.Empty; diff --git a/WinampNowPlayingToFile/NowPlayingToFilePlugin.cs b/WinampNowPlayingToFile/NowPlayingToFilePlugin.cs index 23f34b7..7d14884 100644 --- a/WinampNowPlayingToFile/NowPlayingToFilePlugin.cs +++ b/WinampNowPlayingToFile/NowPlayingToFilePlugin.cs @@ -1,9 +1,9 @@ #nullable enable +using Daniel15.Sharpamp; using System; using System.Reflection; using System.Windows.Forms; -using Daniel15.Sharpamp; using WinampNowPlayingToFile.Business; using WinampNowPlayingToFile.Facade; using WinampNowPlayingToFile.Presentation; diff --git a/WinampNowPlayingToFile/Presentation/SettingsDialog.Designer.cs b/WinampNowPlayingToFile/Presentation/SettingsDialog.Designer.cs index 291cd26..71d1395 100644 --- a/WinampNowPlayingToFile/Presentation/SettingsDialog.Designer.cs +++ b/WinampNowPlayingToFile/Presentation/SettingsDialog.Designer.cs @@ -34,7 +34,6 @@ private void InitializeComponent() System.Windows.Forms.ToolStripMenuItem filenameToolStripMenuItem; System.Windows.Forms.ToolStripMenuItem titleToolStripMenuItem; System.Windows.Forms.ToolStripMenuItem yearToolStripMenuItem; - System.Windows.Forms.ToolStripMenuItem otherToolStripMenuItem; System.Windows.Forms.ToolStripMenuItem albumArtistToolStripMenuItem; System.Windows.Forms.ToolStripMenuItem bitrateToolStripMenuItem; System.Windows.Forms.ToolStripMenuItem bpmToolStripMenuItem; @@ -66,7 +65,9 @@ private void InitializeComponent() System.Windows.Forms.ToolStripMenuItem trackToolStripMenuItem; System.Windows.Forms.ToolStripMenuItem typeToolStripMenuItem; System.Windows.Forms.ToolStripMenuItem vbrToolStripMenuItem; + System.Windows.Forms.ToolStripMenuItem elapsedToolStripMenuItem; System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SettingsDialog)); + this.otherToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.fileBasenameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.fileBasenameWithoutExtensionToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.writeToFileLabel = new System.Windows.Forms.Label(); @@ -99,7 +100,6 @@ private void InitializeComponent() filenameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); titleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); yearToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - otherToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); albumArtistToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); bitrateToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); bpmToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -131,6 +131,7 @@ private void InitializeComponent() trackToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); typeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); vbrToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + elapsedToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.insertTemplatePlaceholderMenu.SuspendLayout(); this.SuspendLayout(); // @@ -170,47 +171,6 @@ private void InitializeComponent() yearToolStripMenuItem.Size = new System.Drawing.Size(155, 22); yearToolStripMenuItem.Text = "Year"; // - // otherToolStripMenuItem - // - otherToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - albumArtistToolStripMenuItem, - bitrateToolStripMenuItem, - bpmToolStripMenuItem, - categoryToolStripMenuItem, - commentToolStripMenuItem, - composerToolStripMenuItem, - conductorToolStripMenuItem, - directorToolStripMenuItem, - discToolStripMenuItem, - familyToolStripMenuItem, - this.fileBasenameToolStripMenuItem, - this.fileBasenameWithoutExtensionToolStripMenuItem, - gainToolStripMenuItem, - genreToolStripMenuItem, - isrcToolStripMenuItem, - keyToolStripMenuItem, - lengthToolStripMenuItem, - losslessToolStripMenuItem, - lyricistToolStripMenuItem, - mediaToolStripMenuItem, - producerToolStripMenuItem, - publisherToolStripMenuItem, - ratingToolStripMenuItem, - replayGainAlbumGainToolStripMenuItem, - replayGainAlbumPeakToolStripMenuItem, - replayGainTrackGainToolStripMenuItem, - replayGainTrackPeakToolStripMenuItem, - stereoToolStripMenuItem, - subtitleToolStripMenuItem, - toolToolStripMenuItem, - trackToolStripMenuItem, - typeToolStripMenuItem, - vbrToolStripMenuItem}); - otherToolStripMenuItem.Name = "otherToolStripMenuItem"; - otherToolStripMenuItem.Size = new System.Drawing.Size(155, 22); - otherToolStripMenuItem.Text = "More"; - otherToolStripMenuItem.DropDownItemClicked += new System.Windows.Forms.ToolStripItemClickedEventHandler(this.onTemplateMenuSelection); - // // albumArtistToolStripMenuItem // albumArtistToolStripMenuItem.Name = "albumArtistToolStripMenuItem"; @@ -279,22 +239,6 @@ private void InitializeComponent() familyToolStripMenuItem.Text = "Family"; familyToolStripMenuItem.ToolTipText = "e.g. \"MPEG Layer 3 Audio File\""; // - // fileBasenameToolStripMenuItem - // - this.fileBasenameToolStripMenuItem.Name = "fileBasenameToolStripMenuItem"; - this.fileBasenameToolStripMenuItem.Size = new System.Drawing.Size(247, 22); - this.fileBasenameToolStripMenuItem.Tag = "FileBasename"; - this.fileBasenameToolStripMenuItem.Text = "File basename"; - this.fileBasenameToolStripMenuItem.ToolTipText = "Name of file without path, e.g. \"Song.mp3\""; - // - // fileBasenameWithoutExtensionToolStripMenuItem - // - this.fileBasenameWithoutExtensionToolStripMenuItem.Name = "fileBasenameWithoutExtensionToolStripMenuItem"; - this.fileBasenameWithoutExtensionToolStripMenuItem.Size = new System.Drawing.Size(247, 22); - this.fileBasenameWithoutExtensionToolStripMenuItem.Tag = "FileBasenameWithoutExtension"; - this.fileBasenameWithoutExtensionToolStripMenuItem.Text = "File basename without extension"; - this.fileBasenameWithoutExtensionToolStripMenuItem.ToolTipText = "Name of file without path or extension, e.g. \"Song\""; - // // gainToolStripMenuItem // gainToolStripMenuItem.Name = "gainToolStripMenuItem"; @@ -445,6 +389,73 @@ private void InitializeComponent() vbrToolStripMenuItem.Text = "VBR"; vbrToolStripMenuItem.ToolTipText = "\"0\" (constant bitrate) or \"1\" (variable bitrate)"; // + // elapsedToolStripMenuItem + // + elapsedToolStripMenuItem.Name = "elapsedToolStripMenuItem"; + elapsedToolStripMenuItem.Size = new System.Drawing.Size(247, 22); + elapsedToolStripMenuItem.Tag = "Elapsed:m\\:ss"; + elapsedToolStripMenuItem.Text = "Elapsed"; + elapsedToolStripMenuItem.ToolTipText = "Playback time position of the current media with millisecond resolution, updated " + + "every second. To be formatted as a .NET TimeSpan."; + // + // otherToolStripMenuItem + // + this.otherToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + albumArtistToolStripMenuItem, + bitrateToolStripMenuItem, + bpmToolStripMenuItem, + categoryToolStripMenuItem, + commentToolStripMenuItem, + composerToolStripMenuItem, + conductorToolStripMenuItem, + directorToolStripMenuItem, + discToolStripMenuItem, + elapsedToolStripMenuItem, + familyToolStripMenuItem, + this.fileBasenameToolStripMenuItem, + this.fileBasenameWithoutExtensionToolStripMenuItem, + gainToolStripMenuItem, + genreToolStripMenuItem, + isrcToolStripMenuItem, + keyToolStripMenuItem, + lengthToolStripMenuItem, + losslessToolStripMenuItem, + lyricistToolStripMenuItem, + mediaToolStripMenuItem, + producerToolStripMenuItem, + publisherToolStripMenuItem, + ratingToolStripMenuItem, + replayGainAlbumGainToolStripMenuItem, + replayGainAlbumPeakToolStripMenuItem, + replayGainTrackGainToolStripMenuItem, + replayGainTrackPeakToolStripMenuItem, + stereoToolStripMenuItem, + subtitleToolStripMenuItem, + toolToolStripMenuItem, + trackToolStripMenuItem, + typeToolStripMenuItem, + vbrToolStripMenuItem}); + this.otherToolStripMenuItem.Name = "otherToolStripMenuItem"; + this.otherToolStripMenuItem.Size = new System.Drawing.Size(155, 22); + this.otherToolStripMenuItem.Text = "More"; + this.otherToolStripMenuItem.DropDownItemClicked += new System.Windows.Forms.ToolStripItemClickedEventHandler(this.onTemplateMenuSelection); + // + // fileBasenameToolStripMenuItem + // + this.fileBasenameToolStripMenuItem.Name = "fileBasenameToolStripMenuItem"; + this.fileBasenameToolStripMenuItem.Size = new System.Drawing.Size(247, 22); + this.fileBasenameToolStripMenuItem.Tag = "FileBasename"; + this.fileBasenameToolStripMenuItem.Text = "File basename"; + this.fileBasenameToolStripMenuItem.ToolTipText = "Name of file without path, e.g. \"Song.mp3\""; + // + // fileBasenameWithoutExtensionToolStripMenuItem + // + this.fileBasenameWithoutExtensionToolStripMenuItem.Name = "fileBasenameWithoutExtensionToolStripMenuItem"; + this.fileBasenameWithoutExtensionToolStripMenuItem.Size = new System.Drawing.Size(247, 22); + this.fileBasenameWithoutExtensionToolStripMenuItem.Tag = "FileBasenameWithoutExtension"; + this.fileBasenameWithoutExtensionToolStripMenuItem.Text = "File basename without extension"; + this.fileBasenameWithoutExtensionToolStripMenuItem.ToolTipText = "Name of file without path or extension, e.g. \"Song\""; + // // writeToFileLabel // this.writeToFileLabel.AutoSize = true; @@ -563,7 +574,7 @@ private void InitializeComponent() filenameToolStripMenuItem, titleToolStripMenuItem, yearToolStripMenuItem, - otherToolStripMenuItem, + this.otherToolStripMenuItem, this.toolStripSeparator1, this.ifToolStripMenuItem, this.ifElseToolStripMenuItem, @@ -612,7 +623,7 @@ private void InitializeComponent() // // explanationLabel // - this.explanationLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + this.explanationLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.explanationLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.explanationLabel.Location = new System.Drawing.Point(22, 148); @@ -624,7 +635,7 @@ private void InitializeComponent() // // horizontalRule1 // - this.horizontalRule1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + this.horizontalRule1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.horizontalRule1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.horizontalRule1.Location = new System.Drawing.Point(17, 136); @@ -703,7 +714,6 @@ private void InitializeComponent() this.Controls.Add(this.textBrowseButton); this.Controls.Add(this.albumArtLabel); this.Controls.Add(this.writeToFileLabel); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MaximizeBox = false; this.MinimizeBox = false; @@ -745,5 +755,6 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem ifElseToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem fileBasenameToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem fileBasenameWithoutExtensionToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem otherToolStripMenuItem; } } \ No newline at end of file diff --git a/WinampNowPlayingToFile/Presentation/SettingsDialog.cs b/WinampNowPlayingToFile/Presentation/SettingsDialog.cs index 51e3716..cc4db14 100644 --- a/WinampNowPlayingToFile/Presentation/SettingsDialog.cs +++ b/WinampNowPlayingToFile/Presentation/SettingsDialog.cs @@ -1,5 +1,6 @@ #nullable enable +using Mustache; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -10,9 +11,9 @@ using System.Linq; using System.Text; using System.Windows.Forms; -using Mustache; using WinampNowPlayingToFile.Facade; using WinampNowPlayingToFile.Settings; +using Timer = System.Timers.Timer; namespace WinampNowPlayingToFile.Presentation; @@ -20,6 +21,7 @@ public partial class SettingsDialog: Form { private readonly ISettings settings; private readonly WinampControllerImpl winampController; + private readonly Timer renderTextTimer = new() { Enabled = true, Interval = 1000 }; private static readonly FormatCompiler TEMPLATE_COMPILER = new(); @@ -38,6 +40,7 @@ public partial class SettingsDialog: Form { { "category", "Rock" }, { "composer", "U2" }, { "disc", 1 }, + { "elapsed", TimeSpan.FromMilliseconds(251422 / 2.0) }, { "family", "MPEG Layer 3 Audio File" }, { "filebasename", "Exit.mp3" }, { "filebasenamewithoutextension", "Exit" }, @@ -86,6 +89,7 @@ private void SettingsDialog_Load(object sender, EventArgs e) { templateEditor.Select(templateEditor.TextLength, 0); winampController.songChanged += delegate { renderPreview(); }; + renderTextTimer.Elapsed += delegate { renderPreview(); }; applyButton.Enabled = false; } @@ -158,8 +162,8 @@ private void showTemplateMenu(object sender, EventArgs e) { private void onTemplateMenuSelection(object sender, ToolStripItemClickedEventArgs e) { if (e.ClickedItem == helpToolStripMenuItem) { - Process.Start("https://handlebarsjs.com/guide/#language-features"); - } else { + Process.Start("https://github.com/jehugaleahsa/mustache-sharp/blob/v1.0/README.md#placeholders"); + } else if (e.ClickedItem != otherToolStripMenuItem) { string textToInsert; if (e.ClickedItem == newLineToolStripMenuItem) { textToInsert = "#newline"; @@ -235,4 +239,9 @@ private void onFilenameChange(object sender, EventArgs e) { onFormDirty(); } + protected override void OnClosed(EventArgs e) { + renderTextTimer.Dispose(); + base.OnClosed(e); + } + } \ No newline at end of file diff --git a/WinampNowPlayingToFile/Presentation/SettingsDialog.resx b/WinampNowPlayingToFile/Presentation/SettingsDialog.resx index 0c079c1..b58ce05 100644 --- a/WinampNowPlayingToFile/Presentation/SettingsDialog.resx +++ b/WinampNowPlayingToFile/Presentation/SettingsDialog.resx @@ -132,9 +132,6 @@ False - - False - False @@ -228,6 +225,9 @@ False + + False + 17, 21 diff --git a/WinampNowPlayingToFile/Properties/AssemblyInfo.cs b/WinampNowPlayingToFile/Properties/AssemblyInfo.cs index 36a68fa..3e701a8 100644 --- a/WinampNowPlayingToFile/Properties/AssemblyInfo.cs +++ b/WinampNowPlayingToFile/Properties/AssemblyInfo.cs @@ -32,6 +32,6 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.1.0.0")] -[assembly: AssemblyFileVersion("2.1.0.0")] +[assembly: AssemblyVersion("2.2.0.0")] +[assembly: AssemblyFileVersion("2.2.0.0")] [assembly: InternalsVisibleTo("Test")] \ No newline at end of file