diff --git a/audio-service/metadata.json b/audio-service/metadata.json index c47f133..aad62ef 100644 --- a/audio-service/metadata.json +++ b/audio-service/metadata.json @@ -16,7 +16,7 @@ { "endTime": 30, "filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260220_193822.wav", - "name": "Pee pee poo poo", + "name": "Pee pee\npoo poo", "playbackType": "playStop", "startTime": 27.587412587412587, "volume": 1 diff --git a/audio-service/src/routes/__pycache__/recording.cpython-313.pyc b/audio-service/src/routes/__pycache__/recording.cpython-313.pyc index d15b537..d45df46 100644 Binary files a/audio-service/src/routes/__pycache__/recording.cpython-313.pyc and b/audio-service/src/routes/__pycache__/recording.cpython-313.pyc differ diff --git a/audio-service/src/routes/recording.py b/audio-service/src/routes/recording.py index 0922a20..e5254b0 100644 --- a/audio-service/src/routes/recording.py +++ b/audio-service/src/routes/recording.py @@ -40,5 +40,14 @@ def recording_delete(): try: os.remove(filename) return jsonify({'status': 'success'}) + except Exception as e: + return jsonify({'status': 'error', 'message': str(e)}), 400 + +@recording_bp.route('/playback/start', methods=['POST']) +def playback_start(): + print('HTTP: Starting audio playback') + try: + # os.remove(filename) + return jsonify({'status': 'success'}) except Exception as e: return jsonify({'status': 'error', 'message': str(e)}), 400 \ No newline at end of file diff --git a/electron-ui/src/renderer/components/AudioTrimer.tsx b/electron-ui/src/renderer/components/AudioTrimer.tsx index af5954b..1c63530 100644 --- a/electron-ui/src/renderer/components/AudioTrimer.tsx +++ b/electron-ui/src/renderer/components/AudioTrimer.tsx @@ -301,18 +301,15 @@ export default function AudioTrimmer({ > Edit Clip Name - setNameInput(e.target.value)} - onKeyDown={(e) => { - if (e.key === 'Enter') handleDialogSave(); - }} + rows={3} onFocus={(event) => event.target.select()} aria-label="Edit clip name" + style={{ minHeight: '3em' }} /> diff --git a/stream_deck_plugin/.vs/ClipTrimDotNet/FileContentIndex/5ba82e2c-dcf4-4055-a830-639383c8c842.vsidx b/stream_deck_plugin/.vs/ClipTrimDotNet/FileContentIndex/5ba82e2c-dcf4-4055-a830-639383c8c842.vsidx new file mode 100644 index 0000000..380d8a3 Binary files /dev/null and b/stream_deck_plugin/.vs/ClipTrimDotNet/FileContentIndex/5ba82e2c-dcf4-4055-a830-639383c8c842.vsidx differ diff --git a/stream_deck_plugin/.vs/ClipTrimDotNet/FileContentIndex/f41a6896-d9b5-4af7-8dec-d0296008b1ac.vsidx b/stream_deck_plugin/.vs/ClipTrimDotNet/FileContentIndex/f41a6896-d9b5-4af7-8dec-d0296008b1ac.vsidx new file mode 100644 index 0000000..ca74531 Binary files /dev/null and b/stream_deck_plugin/.vs/ClipTrimDotNet/FileContentIndex/f41a6896-d9b5-4af7-8dec-d0296008b1ac.vsidx differ diff --git a/stream_deck_plugin/ClipTrimDotNet/Client/ClipMetadata.cs b/stream_deck_plugin/ClipTrimDotNet/Client/ClipMetadata.cs new file mode 100644 index 0000000..36f6643 --- /dev/null +++ b/stream_deck_plugin/ClipTrimDotNet/Client/ClipMetadata.cs @@ -0,0 +1,42 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ClipTrimDotNet.Client +{ + public enum PlaybackType + { + playStop, + playOverlap + } + public class ClipMetadata + { + [JsonProperty(PropertyName = "filename")] + public string Filename { get; set; } + + + [JsonProperty(PropertyName = "name")] + public string Name { get; set; } + + + [JsonProperty(PropertyName = "volume")] + public double Volume { get; set; } = 1.0; + + + [JsonProperty(PropertyName = "startTime")] + public double StartTime { get; set; } = 0.0; + + + [JsonProperty(PropertyName = "endTime")] + public double EndTime { get; set; } = 0.0; + + + [JsonProperty(PropertyName = "playbackType")] + [JsonConverter(typeof(StringEnumConverter))] + public PlaybackType PlaybackType { get; set; } = PlaybackType.playStop; + } +} diff --git a/stream_deck_plugin/ClipTrimDotNet/Client/ClipTrimClient.cs b/stream_deck_plugin/ClipTrimDotNet/Client/ClipTrimClient.cs new file mode 100644 index 0000000..b369dc0 --- /dev/null +++ b/stream_deck_plugin/ClipTrimDotNet/Client/ClipTrimClient.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace ClipTrimDotNet.Client +{ + public class ClipTrimClient + { + private static ClipTrimClient? instance; + public static ClipTrimClient Instance + { + get + { + if (instance == null) + { + instance = new ClipTrimClient(); + } + return instance; + } + } + + private HttpClient httpClient; + + public ClipTrimClient() + { + httpClient = new HttpClient() + { + BaseAddress = new Uri("http://localhost:5010/"), + Timeout = TimeSpan.FromSeconds(10) + }; + Task.Run(ShortPoll); + } + + public async Task ShortPoll() + { + while (true) + { + await GetMetadata(); + await Task.Delay(TimeSpan.FromSeconds(5)); await Task.Delay(TimeSpan.FromSeconds(5)); + + } + } + + public List Collections { get; private set; } = new List(); + public CollectionMetaData? SelectedCollection { get; private set; } + public int PageIndex { get; private set; } = 0; + private async Task GetMetadata() + { + try + { + var response = await httpClient.GetAsync("meta"); + if (response.IsSuccessStatusCode) + { + var json = await response.Content.ReadAsStringAsync(); + dynamic collections = JsonConvert.DeserializeObject(json); + collections = collections.collections; + Collections = JsonConvert.DeserializeObject>(collections.ToString()); + } + } + catch (Exception ex) + { + //Logger.Instance.LogMessage(TracingLevel.INFO, $"Error pinging ClipTrim API: {ex.Message}"); + return; + } + + } + + public List GetCollectionNames() + { + //await GetMetadata(); + return Collections.Select(x => x.Name).ToList(); + } + + public void SetSelectedCollectionByName(string name) + { + var collection = Collections.FirstOrDefault(x => x.Name == name); + if (collection != null) + { + SelectedCollection = collection; + PageIndex = 0; + } + } + + public ClipMetadata? GetClipByPagedIndex(int index) + { + if (SelectedCollection == null) return null; + int clipIndex = PageIndex * 10 + index; + if (clipIndex >= 0 && clipIndex < SelectedCollection.Clips.Count) + { + return SelectedCollection.Clips[clipIndex]; + } + return null; + } + + public async void PlayClip(ClipMetadata? metadata) + { + if (metadata == null) return; + + var response = await httpClient.PostAsync("playback/start", new StringContent(JsonConvert.SerializeObject(metadata), Encoding.UTF8, "application/json")); + if (!response.IsSuccessStatusCode) + { + //Logger.Instance.LogMessage(TracingLevel.INFO, $"Error playing clip: {response.ReasonPhrase}"); + } + } + } +} diff --git a/stream_deck_plugin/ClipTrimDotNet/Client/CollectionMetaData.cs b/stream_deck_plugin/ClipTrimDotNet/Client/CollectionMetaData.cs new file mode 100644 index 0000000..f2769b7 --- /dev/null +++ b/stream_deck_plugin/ClipTrimDotNet/Client/CollectionMetaData.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ClipTrimDotNet.Client +{ + public class CollectionMetaData + { + [JsonProperty(PropertyName = "name")] + public string Name { get; set; } + + + [JsonProperty(PropertyName = "clips")] + public List Clips { get; set; } = new List(); + + + [JsonProperty(PropertyName = "id")] + public int Id { get; set; } + } +} diff --git a/stream_deck_plugin/ClipTrimDotNet/ClipTrimDotNet.csproj b/stream_deck_plugin/ClipTrimDotNet/ClipTrimDotNet.csproj index d485dce..29f0f39 100644 --- a/stream_deck_plugin/ClipTrimDotNet/ClipTrimDotNet.csproj +++ b/stream_deck_plugin/ClipTrimDotNet/ClipTrimDotNet.csproj @@ -13,6 +13,7 @@ 512 true true + enable @@ -63,20 +64,20 @@ ..\packages\NAudio.WinMM.2.2.1\lib\netstandard2.0\NAudio.WinMM.dll - ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll - - ..\packages\NLog.5.2.8\lib\net46\NLog.dll + + ..\packages\NLog.6.0.5\lib\net46\NLog.dll - - ..\packages\StreamDeck-Tools.6.2.0\lib\netstandard2.0\StreamDeckTools.dll + + ..\packages\StreamDeck-Tools.6.3.2\lib\netstandard2.0\StreamDeckTools.dll - - ..\packages\System.Drawing.Common.8.0.1\lib\net462\System.Drawing.Common.dll + + ..\packages\System.Drawing.Common.9.0.10\lib\net462\System.Drawing.Common.dll @@ -97,6 +98,9 @@ + + + @@ -150,8 +154,7 @@ - npm run stop -timeout /t 1 /nobreak + npm run stop npm run start diff --git a/stream_deck_plugin/ClipTrimDotNet/Player.cs b/stream_deck_plugin/ClipTrimDotNet/Player.cs index bec8efc..3c83e9b 100644 --- a/stream_deck_plugin/ClipTrimDotNet/Player.cs +++ b/stream_deck_plugin/ClipTrimDotNet/Player.cs @@ -1,5 +1,6 @@ using BarRaider.SdTools; using BarRaider.SdTools.Wrappers; +using ClipTrimDotNet.Client; using NAudio.CoreAudioApi.Interfaces; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -18,9 +19,8 @@ namespace ClipTrimDotNet public class Player : KeypadBase { - private TitleParameters? titleParameters = null; - private string userTitle; - private static int counter = 0; + private ClipMetadata? metadata; + private KeyCoordinates coordinates; private class PluginSettings { public static PluginSettings CreateDefaultSettings() @@ -62,6 +62,7 @@ namespace ClipTrimDotNet { this.settings = payload.Settings.ToObject(); } + this.coordinates = payload.Coordinates; GlobalSettingsManager.Instance.RequestGlobalSettings(); CheckFile(); } @@ -71,34 +72,43 @@ namespace ClipTrimDotNet Tools.AutoPopulateSettings(GlobalSettings.Instance, e.Settings); } + public int GetIndex() + { + return Math.Max((coordinates.Row - 1) * 5 + coordinates.Column, 0); + } + private async void CheckFile() { - if (settings == null || GlobalSettings.Instance.BasePath == null || GlobalSettings.Instance.ProfileName ==null) return; + //if (settings == null || GlobalSettings.Instance.ProfileName ==null) return; + metadata = ClipTrimClient.Instance.GetClipByPagedIndex(GetIndex()); + await Connection.SetTitleAsync($"{metadata?.Name ?? ""}"); + + return; - var files = Directory.GetFiles(Path.Combine(Path.GetDirectoryName(GlobalSettings.Instance.BasePath), GlobalSettings.Instance.ProfileName), "*.wav", SearchOption.TopDirectoryOnly) - .OrderBy(file => File.GetCreationTime(file)) - .ToArray(); - int? i = this.settings.Index; - string new_path = ""; - if (i != null && i >= 0 && i < files.Length) - { - new_path = files[i ?? 0]; - } + //var files = Directory.GetFiles(Path.Combine(Path.GetDirectoryName(GlobalSettings.Instance.BasePath), GlobalSettings.Instance.ProfileName), "*.wav", SearchOption.TopDirectoryOnly) + // .OrderBy(file => File.GetCreationTime(file)) + // .ToArray(); + //int? i = this.settings.Index; + //string new_path = ""; + //if (i != null && i >= 0 && i < files.Length) + //{ + // new_path = files[i ?? 0]; + //} - await Connection.SetTitleAsync(Path.GetFileNameWithoutExtension(new_path)); - if (new_path != settings.Path) - { - settings.Path = new_path; - if(new_path != "") - { - FileEntry opts = GlobalSettings.Instance.GetFileOptionsInCurrentProfile(new_path); - settings.Volume = opts.Volume; - settings.PlayType = opts.Playtype; - } - await SaveSettings(); - } + //await Connection.SetTitleAsync(Path.GetFileNameWithoutExtension(new_path)); + //if (new_path != settings.Path) + //{ + // settings.Path = new_path; + // if(new_path != "") + // { + // FileEntry opts = GlobalSettings.Instance.GetFileOptionsInCurrentProfile(new_path); + // settings.Volume = opts.Volume; + // settings.PlayType = opts.Playtype; + // } + // await SaveSettings(); + //} } @@ -109,8 +119,8 @@ namespace ClipTrimDotNet private void Connection_OnTitleParametersDidChange(object sender, SDEventReceivedEventArgs e) { - titleParameters = e.Event?.Payload?.TitleParameters; - userTitle = e.Event?.Payload?.Title; + //titleParameters = e.Event?.Payload?.TitleParameters; + //userTitle = e.Event?.Payload?.Title; } public override void Dispose() @@ -124,15 +134,16 @@ namespace ClipTrimDotNet { //Logger.Instance.LogMessage(TracingLevel.INFO, "Key Pressedd"); Tools.AutoPopulateSettings(settings, payload.Settings); - // Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(settings)); - try - { - WavPlayer.Instance.Play(settings.Path, GlobalSettings.Instance.OutputDevice, settings.Volume, settings.PlayType == "Play/Overlap" ? WavPlayer.PlayMode.PlayOverlap : WavPlayer.PlayMode.PlayStop); - } - catch - { + // Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(settings)); + ClipTrimClient.Instance.PlayClip(metadata); + //try + //{ + // WavPlayer.Instance.Play(settings.Path, GlobalSettings.Instance.OutputDevice, settings.Volume, settings.PlayType == "Play/Overlap" ? WavPlayer.PlayMode.PlayOverlap : WavPlayer.PlayMode.PlayStop); + //} + //catch + //{ - } + //} } diff --git a/stream_deck_plugin/ClipTrimDotNet/ProfileSwitcher.cs b/stream_deck_plugin/ClipTrimDotNet/ProfileSwitcher.cs index d1d2586..e22e515 100644 --- a/stream_deck_plugin/ClipTrimDotNet/ProfileSwitcher.cs +++ b/stream_deck_plugin/ClipTrimDotNet/ProfileSwitcher.cs @@ -1,5 +1,6 @@ using BarRaider.SdTools; using BarRaider.SdTools.Wrappers; +using ClipTrimDotNet.Client; using NAudio.CoreAudioApi.Interfaces; using NAudio.Wave; using Newtonsoft.Json; @@ -59,8 +60,8 @@ namespace ClipTrimDotNet private async void SetTitle() { - - await Connection.SetTitleAsync(settings.ProfileName); + + await Connection.SetTitleAsync(settings.ProfileName + " A"); } private async void Connection_OnSendToPlugin(object sender, SDEventReceivedEventArgs e) @@ -68,8 +69,9 @@ namespace ClipTrimDotNet //Logger.Instance.LogMessage(TracingLevel.INFO, "get profiles"); if (e.Event.Payload["event"].ToString() == "getProfiles") { - string basePath = "C:\\Users\\mickl\\Music\\clips"; - var files = Directory.GetDirectories(basePath, "*", SearchOption.TopDirectoryOnly).Select(x => Path.GetFileNameWithoutExtension(x)).Where(x => x != "original"); + //string basePath = "C:\\Users\\mickl\\Music\\clips"; + //var files = Directory.GetDirectories(basePath, "*", SearchOption.TopDirectoryOnly).Select(x => Path.GetFileNameWithoutExtension(x)).Where(x => x != "original"); + var files = ClipTrimClient.Instance.GetCollectionNames(); var items = files.Select(x => new DataSourceItem { label = x, value = x}); var obj = new JObject(); obj["event"] = "getProfiles"; @@ -110,6 +112,7 @@ namespace ClipTrimDotNet //Logger.Instance.LogMessage(TracingLevel.INFO, "KeyPressed"); //Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(settings)); //Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(GlobalSettings.Instance)); + ClipTrimClient.Instance.SetSelectedCollectionByName(settings.ProfileName); GlobalSettings.Instance.SetCurrentProfile(settings.ProfileName); Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(GlobalSettings.Instance)); diff --git a/stream_deck_plugin/ClipTrimDotNet/packages.config b/stream_deck_plugin/ClipTrimDotNet/packages.config index c2b7e68..3166d2a 100644 --- a/stream_deck_plugin/ClipTrimDotNet/packages.config +++ b/stream_deck_plugin/ClipTrimDotNet/packages.config @@ -9,10 +9,10 @@ - - - - + + + + \ No newline at end of file