using System.Collections.Concurrent; using System.Data; using System.Diagnostics; using System.Net; using System.Reflection.Metadata.Ecma335; using System.Runtime.CompilerServices; using System.Text; using System.Text.RegularExpressions; using System.Timers; using System.Xml.Schema; using Newtonsoft.Json; namespace placeholdervo { public partial class Program { [GeneratedRegex("^(\\[|#)")] private static partial Regex NonTextLine(); public static Config conf; private static string workingDir = "./"; private static HttpClient hc; private static ConcurrentQueue scriptFragmentFiles = new ConcurrentQueue(); private static ConcurrentQueue titleCardLines = new ConcurrentQueue(); private static ConcurrentDictionary filePickups = new ConcurrentDictionary(); private static CancellationToken scriptFileCancellationToken; //from when I cut it up into separate files // private static async void ApiCalls() // { // 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"); // 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; // } // } // } ///mostly just to give myself the reminder about paths ///the *complete path* of the awaited file. you might want conf.sync_dropoff ///the *complete path* to move the file to. private static async void awaitFile(string src, string dest) { filePickups[src] = dest; } private static async void filePickup() { while(true) { foreach(var srcKey in filePickups.Keys) { // var files = Directory.GetFiles(conf.sync_dropoff); // Console.WriteLine($"files listed: {string.Join(", ", files)}"); // Console.WriteLine($"hoping for: {string.Join(", ", filePickups.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()]}"); if(File.Exists(srcKey)) { Console.WriteLine($"found {srcKey}"); string dest; if (filePickups.TryRemove(srcKey, out dest)) { File.Move(srcKey, dest); } else { Console.Error.WriteLine($"Failed to remove {srcKey} from filepickups. Unrecoverable, I think."); Environment.Exit(-1); } } } if(scriptFileCancellationToken.IsCancellationRequested) { return; } System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); } } public static async Task Main(string[] args) { conf = JsonConvert.DeserializeObject( File.ReadAllText( AppDomain.CurrentDomain.BaseDirectory + "appsettings.json")) ?? new Config(); hc = new HttpClient(){ BaseAddress = new Uri(conf.speech_service)}; var scriptPath = args?.FirstOrDefault(); if(string.IsNullOrWhiteSpace(scriptPath)) { 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 lines = File.ReadAllLines(scriptPath) .Append("\n").Append("\n"); var primaryVOLines = new List(); var titlecardUnprocessed = new List(); var titlecardLines = new List(); var directiveLines = new List(); var altVOLines = new List(); var noteLines = new List(); foreach(var l in lines) { if(l.StartsWith('#')) { titlecardUnprocessed.Add(l); } else if (l.StartsWith('[')) { directiveLines.Add(l); } else { //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 = $"{scriptBasename}-primaryVO.txt"; File.WriteAllLines(scriptStripped, primaryVOLines); Task.WaitAny(PrimaryVO(scriptStripped)); var titleLevels = new List(){0}; var titleIncrementDepth = 0; foreach(var l in titlecardUnprocessed) { 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}"); titlecardLines.Add(TitleCardText); //TODO: tc command } else { titleIncrementDepth++; } } } foreach(var l in directiveLines) { 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") { //TODO: note command noteLines.Add(parameterText); Console.WriteLine($"on screen note: {parameterText}"); } else { altVOLines.Add(parameterText); Console.WriteLine($"alt VA: {parameterText}"); } } } if(altVOLines?.Count > 0) { //TODO: alt va command with altVOLines File.WriteAllLines($"{scriptBasename}-altVO.txt", altVOLines); } // execute them all //Task.Run(OfflineStuff); //Task.Run(ApiCalls); var fpTask = Task.Run(filePickup); // 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"); } private static async Task PrimaryVO(string scriptStripped) { HttpContent fileStreamContent = new StreamContent(File.OpenRead(scriptStripped)); 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 { Console.WriteLine($"success; {await response.Content.ReadAsStringAsync()}."); //TODO: add to queue to watch for? } } } } }