diff --git a/.vscode/launch.json b/.vscode/launch.json index e25875d..a81019a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "build", - "program": "${workspaceFolder}/bin/Debug/net8.0/placeholder-VO.dll", + "program": "${workspaceFolder}/bin/Debug/net8.0/script-splitter.dll", "args": [], "cwd": "${workspaceFolder}", "console": "internalConsole", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 554840c..ff1fe5a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,7 +7,7 @@ "type": "process", "args": [ "build", - "${workspaceFolder}/placeholder-VO.csproj", + "${workspaceFolder}/script-splitter.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary;ForceNoAlign" ], @@ -19,7 +19,7 @@ "type": "process", "args": [ "publish", - "${workspaceFolder}/placeholder-VO.csproj", + "${workspaceFolder}/script-splitter.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary;ForceNoAlign" ], @@ -33,7 +33,7 @@ "watch", "run", "--project", - "${workspaceFolder}/placeholder-VO.csproj" + "${workspaceFolder}/script-splitter.csproj" ], "problemMatcher": "$msCompile" } diff --git a/Program.cs b/Program.cs index 98682de..dfdc0f2 100644 --- a/Program.cs +++ b/Program.cs @@ -7,6 +7,7 @@ using System.Runtime.CompilerServices; using System.Text; using System.Text.RegularExpressions; using System.Timers; +using System.Xml.Schema; using Newtonsoft.Json; @@ -15,104 +16,103 @@ namespace placeholdervo public partial class Program { - [GeneratedRegex("^[^a-zA-Z0-9'\"]")] - private static partial Regex TextLine(); + [GeneratedRegex("^(\\[|#)")] + private static partial Regex NonTextLine(); public static Config conf; private static string workingDir = "./"; private static ConcurrentQueue scriptFragmentFiles = new ConcurrentQueue(); + private static ConcurrentQueue titleCardLines = new ConcurrentQueue(); private static CancellationToken scriptFileCancellationToken; - private static async void webcall() - { - var hc = new HttpClient(){ BaseAddress = new Uri(conf.speech_service)}; - while(true) - { - while(!scriptFragmentFiles.IsEmpty) - { - string scriptFragment; - scriptFragmentFiles.TryDequeue(out scriptFragment); - if(scriptFragment == null) continue; - Console.WriteLine(scriptFragment); + // private static async void webcall() + // { + // var hc = new HttpClient(){ BaseAddress = new Uri(conf.speech_service)}; + // while(true) + // { + // while(!scriptFragmentFiles.IsEmpty) + // { + // string scriptFragment; + // scriptFragmentFiles.TryDequeue(out scriptFragment); + // if(scriptFragment == null) continue; + // Console.WriteLine(scriptFragment); - HttpContent fileStreamContent = new StreamContent(File.OpenRead(scriptFragment)); - using (var formData = new MultipartFormDataContent()) - { - formData.Add(fileStreamContent, "file1", "file1"); + // HttpContent fileStreamContent = new StreamContent(File.OpenRead(scriptFragment)); + // using (var formData = new MultipartFormDataContent()) + // { + // formData.Add(fileStreamContent, "file1", "file1"); - var response = await hc.PostAsync("/speak", formData); - if (!response.IsSuccessStatusCode) - { - Console.Error.WriteLine($"{response.StatusCode} - {response.ReasonPhrase} - {await response.Content.ReadAsStringAsync()}"); - } - else - { - var resp = string.Join(", ", JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync())); - Console.WriteLine($"success; {resp}."); - if(resp != null) - { - scriptFragmentVoiceFiles[resp] = scriptFragment; - Console.WriteLine("Ditching script fragment file."); - File.Delete(scriptFragment); - } - } - } - System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1)); - } + // var response = await hc.PostAsync("/speak", formData); + // if (!response.IsSuccessStatusCode) + // { + // Console.Error.WriteLine($"{response.StatusCode} - {response.ReasonPhrase} - {await response.Content.ReadAsStringAsync()}"); + // } + // else + // { + // var resp = string.Join(", ", JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync())); + // Console.WriteLine($"success; {resp}."); + // if(resp != null) + // { + // scriptFragmentVoiceFiles[resp] = scriptFragment; + // Console.WriteLine("Ditching script fragment file."); + // File.Delete(scriptFragment); + // } + // } + // } + // System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1)); + // } - if(scriptFileCancellationToken.IsCancellationRequested && scriptFragmentFiles.IsEmpty) - { - return; - } - } - } + // if(scriptFileCancellationToken.IsCancellationRequested && scriptFragmentFiles.IsEmpty) + // { + // return; + // } + // } + // } - private static ConcurrentDictionary scriptFragmentVoiceFiles = new ConcurrentDictionary(); - - private static async void filePickup() - { - while(true) - { - while(!scriptFragmentVoiceFiles.IsEmpty) - { - var files = Directory.GetFiles(conf.sync_dropoff); - Console.WriteLine($"files listed: {string.Join(", ", files)}"); - Console.WriteLine($"hoping for: {string.Join(", ", scriptFragmentVoiceFiles.Keys)}"); - // Console.WriteLine($"sanity check: first listed file: {Path.GetFileName(files.FirstOrDefault())}"); - // Console.WriteLine($"sanity check: first key: {scriptFragmentVoiceFiles.Keys.FirstOrDefault()}"); - // Console.WriteLine($"sanity check: first value: {scriptFragmentVoiceFiles[scriptFragmentVoiceFiles.Keys.FirstOrDefault()]}"); - var audioFile = files.FirstOrDefault(f => scriptFragmentVoiceFiles.ContainsKey(Path.GetFileName(f))); - if(!string.IsNullOrWhiteSpace(audioFile)) - { - Console.WriteLine($"found {audioFile}"); - try - { - var bareAudioFile = Path.GetFileName(audioFile); - var destFile = scriptFragmentVoiceFiles[bareAudioFile]; - destFile = Path.GetFileNameWithoutExtension(destFile) + ".wav"; - destFile = Path.Combine(workingDir, destFile); - File.Move(audioFile, destFile); + // private static async void filePickup() + // { + // while(true) + // { + // while(!scriptFragmentVoiceFiles.IsEmpty) + // { + // var files = Directory.GetFiles(conf.sync_dropoff); + // Console.WriteLine($"files listed: {string.Join(", ", files)}"); + // Console.WriteLine($"hoping for: {string.Join(", ", scriptFragmentVoiceFiles.Keys)}"); + // // Console.WriteLine($"sanity check: first listed file: {Path.GetFileName(files.FirstOrDefault())}"); + // // Console.WriteLine($"sanity check: first key: {scriptFragmentVoiceFiles.Keys.FirstOrDefault()}"); + // // Console.WriteLine($"sanity check: first value: {scriptFragmentVoiceFiles[scriptFragmentVoiceFiles.Keys.FirstOrDefault()]}"); + // var audioFile = files.FirstOrDefault(f => scriptFragmentVoiceFiles.ContainsKey(Path.GetFileName(f))); + // if(!string.IsNullOrWhiteSpace(audioFile)) + // { + // Console.WriteLine($"found {audioFile}"); + // try + // { + // var bareAudioFile = Path.GetFileName(audioFile); + // var destFile = scriptFragmentVoiceFiles[bareAudioFile]; + // destFile = Path.GetFileNameWithoutExtension(destFile) + ".wav"; + // destFile = Path.Combine(workingDir, destFile); + // File.Move(audioFile, destFile); - if(!scriptFragmentVoiceFiles.Remove(bareAudioFile, out string throwaway)) - { - Console.WriteLine($"failed to remove {bareAudioFile}"); - } - } - catch(Exception e) - { - Console.Error.WriteLine(e.Message); - } - } - System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); - } - if(scriptFileCancellationToken.IsCancellationRequested) - { - return; - } + // if(!scriptFragmentVoiceFiles.Remove(bareAudioFile, out string throwaway)) + // { + // Console.WriteLine($"failed to remove {bareAudioFile}"); + // } + // } + // catch(Exception e) + // { + // Console.Error.WriteLine(e.Message); + // } + // } + // System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); + // } + // if(scriptFileCancellationToken.IsCancellationRequested) + // { + // return; + // } - System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1)); - } - } + // System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1)); + // } + // } public static async Task Main(string[] args) { @@ -123,63 +123,145 @@ namespace placeholdervo var scriptPath = args?.FirstOrDefault(); if(string.IsNullOrWhiteSpace(scriptPath)) - scriptPath = "./script.txt"; + { + scriptPath = "./script.md"; + if(!File.Exists(scriptPath)) + { + scriptPath = "./script.txt"; + if(!File.Exists(scriptPath)) + { + Console.Error.WriteLine("no script found."); + return; + } + } + } + var scriptBasename = Path.GetFileNameWithoutExtension(scriptPath); workingDir = Path.GetDirectoryName(scriptPath); var cancelSource = new CancellationTokenSource(); scriptFileCancellationToken = cancelSource.Token; - var apiCallThread = new Thread(new ThreadStart(webcall)); - apiCallThread.Start(); - var fileRetrieveThread = new Thread(new ThreadStart(filePickup)); - fileRetrieveThread.Start(); + // var apiCallThread = new Thread(new ThreadStart(webcall)); + // apiCallThread.Start(); + // var fileRetrieveThread = new Thread(new ThreadStart(filePickup)); + // fileRetrieveThread.Start(); - var lines = File.ReadAllLines(scriptPath).Where(l => !TextLine().IsMatch(l)) - .Append("\n").Append("\n"); //pad out file so my tactic for separating doesn't fall off the end of the file - var lineCountMagnitude = (int)Math.Log10(lines.Count()); - - var runningSavedLines = new List(); - var completeSavedLines = new List(); - var iteration = 0; - + var lines = File.ReadAllLines(scriptPath) + .Append("\n").Append("\n"); + var primaryVOLines = new List(); + var titlecardLines = new List(); + var directiveLines = new List(); foreach(var l in lines) { - if(string.IsNullOrWhiteSpace(l)) + if(l.StartsWith('#')) { - if(runningSavedLines.Any(line => !string.IsNullOrWhiteSpace(line))) - { - ++iteration; - //x.ToString("D2") should format x with minimum 2 digits, padded left - var scriptFragment = $"script{iteration.ToString($"D{lineCountMagnitude}")}.txt"; - File.WriteAllLines(scriptFragment, runningSavedLines); - scriptFragmentFiles.Enqueue(scriptFragment); - completeSavedLines.AddRange(runningSavedLines); - } - runningSavedLines = []; + titlecardLines.Add(l); + } + else if (l.StartsWith('[')) + { + directiveLines.Add(l); } else { - runningSavedLines.Add(l); + //as opposed to Environment.NewLine, which will be running on linux, and thus \n. ms speech api cooperates more with \r\n. + l.ReplaceLineEndings("\r\n"); + primaryVOLines.Add(l); } } - var scriptStripped = $"script{0.ToString($"D{lineCountMagnitude}")}.txt"; - File.WriteAllLines(scriptStripped, completeSavedLines); - scriptFragmentFiles.Enqueue(scriptStripped); - cancelSource.Cancel(); - Console.WriteLine("http client \"cancelled\"."); - while(apiCallThread.ThreadState != System.Threading.ThreadState.Stopped) + var scriptStripped = $"{scriptBasename}-primaryVO.txt"; + File.WriteAllLines(scriptStripped, primaryVOLines); + var titleLevels = new List(){0}; + var titleIncrementDepth = 0; + foreach(var l in titlecardLines) { - Console.WriteLine("thread still running. waiting."); - System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); + titleIncrementDepth = 1; + var thisString = l; + while(thisString.StartsWith('#')) + { + thisString = thisString.Substring(1); + if(!thisString.StartsWith('#')) + { + if(titleLevels.Count < titleIncrementDepth) + { + titleLevels = [.. titleLevels, 0]; + } + titleLevels[titleIncrementDepth-1]++; + if(titleLevels.Count > titleIncrementDepth) + { + titleLevels.RemoveRange(titleIncrementDepth, titleLevels.Count - titleIncrementDepth); + } + var TitleCardText = thisString.Trim(); + if(titleLevels.Count > 1) + { + TitleCardText = string.Join('.', titleLevels[1..]) + ": " + TitleCardText; + } + Console.WriteLine($"title card: {TitleCardText}"); + //tc command + } + else + { + titleIncrementDepth++; + } + } } - Console.WriteLine($"api call thread done ({apiCallThread.ThreadState})."); - while(fileRetrieveThread.ThreadState != System.Threading.ThreadState.Stopped) + foreach(var l in directiveLines) { - Console.WriteLine("fileRetrieveThread still running. waiting."); - System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); + var thisLine = l.Trim(); + if(!thisLine.Contains(']')) + { + Console.Error.WriteLine("malformed directive line: "); + Console.WriteLine(thisLine); + continue; + } + if (thisLine.EndsWith(']')) + { + thisLine = thisLine.Trim('[', ']'); + + if (Uri.TryCreate(thisLine, UriKind.Absolute, out Uri asUri) + && (asUri.Scheme == Uri.UriSchemeHttp || asUri.Scheme == Uri.UriSchemeHttps)) + { + Console.WriteLine($"uri: {asUri}. ship off to yt-dlp or project Ose"); + } + else + { + //just a directive, we can't do anything here + Console.WriteLine($"mere directive: {thisLine}"); + } + } + else + { + thisLine = thisLine.TrimStart('['); + var directiveName = thisLine[..thisLine.IndexOf(']')]; + var parameterText = thisLine[(thisLine.IndexOf(']') + 1) ..].Trim(); + if(directiveName == "note") + { + //note command + Console.WriteLine($"on screen note: {parameterText}"); + } + else + { + //alt va command + Console.WriteLine($"alt VA: {parameterText}"); + } + } } - Console.WriteLine($"fileRetrieveThread done ({fileRetrieveThread.ThreadState}). kbai"); + + // cancelSource.Cancel(); + // Console.WriteLine("http client \"cancelled\"."); + // while(apiCallThread.ThreadState != System.Threading.ThreadState.Stopped) + // { + // Console.WriteLine("thread still running. waiting."); + // System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); + // } + // Console.WriteLine($"api call thread done ({apiCallThread.ThreadState})."); + + // while(fileRetrieveThread.ThreadState != System.Threading.ThreadState.Stopped) + // { + // Console.WriteLine("fileRetrieveThread still running. waiting."); + // System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); + // } + // Console.WriteLine($"fileRetrieveThread done ({fileRetrieveThread.ThreadState}). kbai"); } } } diff --git a/placeholder-VO.csproj b/script-splitter.csproj similarity index 65% rename from placeholder-VO.csproj rename to script-splitter.csproj index 51ee873..bbb3b4f 100644 --- a/placeholder-VO.csproj +++ b/script-splitter.csproj @@ -3,13 +3,16 @@ Exe net8.0 - placeholder_VO + script-splitter enable enable - - + + + + Always +