script-splitter/Program.cs

308 lines
13 KiB
C#

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<string> scriptFragmentFiles = new ConcurrentQueue<string>();
private static ConcurrentQueue<string> titleCardLines = new ConcurrentQueue<string>();
private static ConcurrentDictionary<string, string> filePickups = new ConcurrentDictionary<string, string>();
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<string[]>(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;
// }
// }
// }
///<summary>mostly just to give myself the reminder about paths</summary>
///<param name="src">the *complete path* of the awaited file. you might want conf.sync_dropoff</param>
///<param name="dest">the *complete path* to move the file to.</param>
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<Config>(
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<string>();
var titlecardUnprocessed = new List<string>();
var titlecardLines = new List<string>();
var directiveLines = new List<string>();
var altVOLines = new List<string>();
var noteLines = new List<string>();
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<int>(){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?
}
}
}
}
}