rework progress
todo: don't have containers, just have each line be "text" if you want
This commit is contained in:
parent
58b2560051
commit
c4d994f76b
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace director
|
namespace DirectorConfiguration
|
||||||
{
|
{
|
||||||
public class Config
|
public class Config
|
||||||
{
|
{
|
||||||
@ -10,10 +10,8 @@ namespace director
|
|||||||
public string webdav_uri { get; set; }
|
public string webdav_uri { get; set; }
|
||||||
public string webdav_username { get; set; }
|
public string webdav_username { get; set; }
|
||||||
public string webdav_password { get; set; }
|
public string webdav_password { get; set; }
|
||||||
public string calendar_youtube { get; set; }
|
public IEnumerable<string> webdav_calendars { get; set; }
|
||||||
public string calendar_twitch { get; set; }
|
public string workingDirectory { get; set; }
|
||||||
public string calendar_other { get; set; }
|
public IEnumerable<ConfigFileLocator> scheduleConfigs { get; set; }
|
||||||
public string show_template_twitch_streams { get; set; }
|
|
||||||
public Dictionary<string, string> phase_handlers { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
13
DirectorConfiguration/ConfigFileLocator.cs
Normal file
13
DirectorConfiguration/ConfigFileLocator.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace DirectorConfiguration
|
||||||
|
{
|
||||||
|
public class ConfigFileLocator
|
||||||
|
{
|
||||||
|
public string Calendar { get; set; }
|
||||||
|
public Regex EventName { get; set; }
|
||||||
|
public string SchedulableConfiguration { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ using System.IO;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Director
|
namespace director
|
||||||
{
|
{
|
||||||
public class HumanCommunication
|
public class HumanCommunication
|
||||||
{
|
{
|
||||||
|
115
Program.cs
115
Program.cs
@ -6,23 +6,23 @@ using System.Linq;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Director;
|
using DirectorConfiguration;
|
||||||
using franz;
|
using franz;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using ShowHandlers;
|
|
||||||
|
|
||||||
namespace director
|
namespace director
|
||||||
{
|
{
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
//private static Telefranz tf;
|
//private static Telefranz tf;
|
||||||
public static Config conf;
|
public static Config directorConf;
|
||||||
private static TimeSpan calendarNaptime = TimeSpan.FromHours(1);
|
private static TimeSpan calendarNaptime = TimeSpan.FromHours(1);
|
||||||
public static Scratch scratch;
|
public static Scratch scratch;
|
||||||
private static HttpClient httpClient;
|
private static HttpClient httpClient;
|
||||||
private static readonly ConcurrentQueue<Schedulable.Schedulable> workQueue = new ConcurrentQueue<Schedulable.Schedulable>();
|
private static readonly ConcurrentQueue<schedulable.Scheduled> workQueue = new ConcurrentQueue<schedulable.Scheduled>();
|
||||||
private static readonly AutoResetEvent _signal = new AutoResetEvent(false);
|
private static readonly AutoResetEvent _signal = new AutoResetEvent(false);
|
||||||
private const int concurrentWorkers = 5;
|
private const int concurrentWorkers = 5;
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
@ -30,18 +30,18 @@ namespace director
|
|||||||
if (!File.Exists("appsettings.json"))
|
if (!File.Exists("appsettings.json"))
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("appsettings.json was not found!");
|
Console.Error.WriteLine("appsettings.json was not found!");
|
||||||
conf = new Config();
|
directorConf = new DirectorConfiguration.Config();
|
||||||
File.WriteAllText("appsettings.json", JsonConvert.SerializeObject(conf, Formatting.Indented));
|
File.WriteAllText("appsettings.json", JsonConvert.SerializeObject(directorConf, Formatting.Indented));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
conf = JsonConvert.DeserializeObject<Config>(File.ReadAllText("appsettings.json"));
|
directorConf = JsonConvert.DeserializeObject<Config>(File.ReadAllText("appsettings.json"));
|
||||||
HumanCommunication.Configure(conf.call_for_humans_discord_webhook);
|
HumanCommunication.Configure(directorConf.call_for_humans_discord_webhook);
|
||||||
|
|
||||||
httpClient = new HttpClient();
|
httpClient = new HttpClient();
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(
|
||||||
System.Text.Encoding.ASCII.GetBytes($"{conf.webdav_username}:{conf.webdav_password}")));
|
System.Text.Encoding.ASCII.GetBytes($"{directorConf.webdav_username}:{directorConf.webdav_password}")));
|
||||||
|
|
||||||
Telefranz.Configure("scheduler", conf.kafka_bootstrap);
|
Telefranz.Configure("scheduler", directorConf.kafka_bootstrap);
|
||||||
|
|
||||||
scratch = Scratch.LoadScratch();
|
scratch = Scratch.LoadScratch();
|
||||||
|
|
||||||
@ -65,16 +65,14 @@ namespace director
|
|||||||
{
|
{
|
||||||
scratch.agenda.Clear();
|
scratch.agenda.Clear();
|
||||||
}
|
}
|
||||||
Task.WaitAll(
|
|
||||||
checkCalendar(conf.calendar_youtube, "youtube", (ref Schedulable.Schedulable n) =>
|
var calChecks = new List<Task>();
|
||||||
|
foreach (var calendar in directorConf.webdav_calendars)
|
||||||
{
|
{
|
||||||
n.ScedulableType = Schedulable.ScedulableType.YTRelease;
|
calChecks.Add(checkCalendar(calendar));
|
||||||
}),
|
}
|
||||||
checkCalendar(conf.calendar_twitch, "twitch", (ref Schedulable.Schedulable n) =>
|
Task.WaitAll(calChecks.ToArray());
|
||||||
{
|
|
||||||
n.ScedulableType = Schedulable.ScedulableType.TwitchStream;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
lock (scratch)
|
lock (scratch)
|
||||||
{
|
{
|
||||||
scratch.Save();
|
scratch.Save();
|
||||||
@ -90,7 +88,7 @@ namespace director
|
|||||||
//todo: find the perfect lead time.
|
//todo: find the perfect lead time.
|
||||||
if ((s.Showtime - TimeSpan.FromDays(1)) - DateTime.Now <= calendarNaptime)
|
if ((s.Showtime - TimeSpan.FromDays(1)) - DateTime.Now <= calendarNaptime)
|
||||||
{
|
{
|
||||||
var copy = JsonConvert.DeserializeObject<Schedulable.Schedulable>(JsonConvert.SerializeObject(s));
|
var copy = JsonConvert.DeserializeObject<schedulable.Scheduled>(JsonConvert.SerializeObject(s));
|
||||||
workQueue.Enqueue(copy);
|
workQueue.Enqueue(copy);
|
||||||
_signal.Set();
|
_signal.Set();
|
||||||
}
|
}
|
||||||
@ -101,43 +99,42 @@ namespace director
|
|||||||
{
|
{
|
||||||
Console.WriteLine("debug test");
|
Console.WriteLine("debug test");
|
||||||
|
|
||||||
var psuedo = new Schedulable.Schedulable();
|
var psuedo = new schedulable.Scheduled();
|
||||||
psuedo.Showtime = DateTime.Now + TimeSpan.FromSeconds(30);
|
psuedo.Showtime = DateTime.Now + TimeSpan.FromSeconds(30);
|
||||||
var partiallyCopiable = scratch.agenda?.FirstOrDefault(s => s.ScedulableType == Schedulable.ScedulableType.TwitchStream);
|
var partiallyCopiable = scratch.agenda?.FirstOrDefault();
|
||||||
psuedo.Occurrence = partiallyCopiable.Occurrence;
|
psuedo.Occurrence = partiallyCopiable.Occurrence;
|
||||||
psuedo.Occurrence.OccurrenceStart = psuedo.Showtime;
|
psuedo.Occurrence.OccurrenceStart = psuedo.Showtime;
|
||||||
psuedo.Occurrence.OccurrenceEnd = psuedo.Showtime;
|
psuedo.Occurrence.OccurrenceEnd = psuedo.Showtime;
|
||||||
psuedo.ScedulableType = Schedulable.ScedulableType.YTRelease;
|
|
||||||
workQueue.Enqueue(psuedo);
|
workQueue.Enqueue(psuedo);
|
||||||
_signal.Set();
|
_signal.Set();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private delegate void schedulableCreate(ref Schedulable.Schedulable creating);
|
private static async Task checkCalendar(string calendarUri)
|
||||||
private static async Task checkCalendar(string calendarUri, string calLabel, schedulableCreate createSchedulable)
|
|
||||||
{
|
{
|
||||||
//?export is a hack to allow me to access the calendar
|
//?export is a hack to allow me to access the calendar
|
||||||
//it likes to throw an error saying "this is the webDAV interface, use webDAV" at my webDAV client, stopping me from using webDAV.
|
//it likes to throw an error saying "this is the webDAV interface, use webDAV" at my webDAV client, stopping me from using webDAV.
|
||||||
var calString = await httpClient.GetStringAsync(conf.webdav_uri + calendarUri + "?export");
|
Console.WriteLine(calendarUri);
|
||||||
var knownChecklist = new List<Schedulable.Schedulable>();
|
var calString = await httpClient.GetStringAsync(directorConf.webdav_uri + calendarUri + "?export");
|
||||||
|
var knownChecklist = new List<schedulable.Scheduled>();
|
||||||
lock (scratch)
|
lock (scratch)
|
||||||
{
|
{
|
||||||
scratch.Calendars[calLabel] = calString;
|
var calName = iCalHoopJumping.LoadCalendar(calString);
|
||||||
iCalHoopJumping.LoadCalendar(calLabel, calString);
|
scratch.Calendars[calName] = calString;
|
||||||
//todo: I'm pretty sure some library is returning me only things in the future. Verify, and also make sure it's returning things in the present.
|
//todo: I'm pretty sure some library is returning me only things in the future. Verify, and also make sure it's returning things in the present.
|
||||||
foreach (var occurrence in iCalHoopJumping.getOccurrences(calLabel))
|
foreach (var occurrence in iCalHoopJumping.getOccurrences(calName))
|
||||||
{
|
{
|
||||||
var newSchedulable = new Schedulable.Schedulable()
|
var newSchedulable = new schedulable.Scheduled()
|
||||||
{
|
{
|
||||||
Occurrence = occurrence,
|
Occurrence = occurrence,
|
||||||
Showtime = occurrence.OccurrenceStart
|
Showtime = occurrence.OccurrenceStart
|
||||||
};
|
};
|
||||||
var asActualEvent = iCalHoopJumping.parseEvent(calLabel, occurrence.Event);
|
var asActualEvent = iCalHoopJumping.parseEvent(calName, occurrence.Event);
|
||||||
|
|
||||||
if(scratch.agenda.FirstOrDefault(s => iCalHoopJumping.parseEvent(calLabel, s.Occurrence.Event)?.Uid == asActualEvent.Uid) == null)
|
if (scratch.agenda.FirstOrDefault(s => iCalHoopJumping.parseEvent(calName, s.Occurrence.Event)?.Uid == asActualEvent.Uid) == null)
|
||||||
{
|
{
|
||||||
createSchedulable(ref newSchedulable);
|
//createSchedulable(ref newSchedulable);
|
||||||
scratch.agenda.Add(newSchedulable);
|
scratch.agenda.Add(newSchedulable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,47 +142,51 @@ namespace director
|
|||||||
}
|
}
|
||||||
private static void threadwork()
|
private static void threadwork()
|
||||||
{
|
{
|
||||||
Schedulable.Schedulable todo = null;
|
schedulable.Scheduled todo = null;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
_signal.WaitOne(calendarNaptime);
|
_signal.WaitOne(calendarNaptime);
|
||||||
|
|
||||||
if (!workQueue.TryDequeue(out todo)) { continue; }
|
if (!workQueue.TryDequeue(out todo)) { continue; }
|
||||||
|
Console.WriteLine($"threadwork consumes! showtime at {todo.Showtime}, {todo.Occurrence._event.Summary} on {todo.Occurrence.CalendarSourceName}");
|
||||||
|
|
||||||
ShowHandler handler = null;
|
todo.Configuration = findConfig(todo.Occurrence.CalendarSourceName, todo.Occurrence._event.Summary);
|
||||||
switch (todo.ScedulableType)
|
if (todo.Configuration == null)
|
||||||
{
|
{
|
||||||
case Schedulable.ScedulableType.TwitchStream:
|
Console.WriteLine("configuration not found, skipping :(");
|
||||||
Console.WriteLine("it's a twitch stream");
|
|
||||||
handler = new TwitchStreamHandler();
|
|
||||||
break;
|
|
||||||
case Schedulable.ScedulableType.YTRelease:
|
|
||||||
Console.WriteLine("it's a yt release");
|
|
||||||
handler = new YoutubeHandler();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
HumanCommunication.Instance.Say($"unknown schedulable type!\n{JsonConvert.SerializeObject(todo)}", HumanCommunication.LogLevel.Showstopper);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var napLength = (todo.Showtime - handler.LeadTimeDesired) - DateTime.Now;
|
Console.WriteLine("configuration found");
|
||||||
Console.WriteLine($"threadwork consumes! showtime at {todo.Showtime}; napping until {todo.Showtime - handler.LeadTimeDesired} ({napLength})");
|
|
||||||
|
|
||||||
if (napLength.TotalMinutes > 0)
|
var handler = new ShowHandler(todo, directorConf.workingDirectory + "/" + todo.Showtime.ToShortDateString());
|
||||||
{
|
handler.StartHandling();
|
||||||
Task.WaitAll(Task.Delay(napLength));
|
}
|
||||||
}
|
}
|
||||||
Console.WriteLine("places, everyone!");
|
|
||||||
|
|
||||||
|
private static schedulable.Schedulable findConfig(string CalendarSourceName, string eventName)
|
||||||
|
{
|
||||||
|
foreach (var locator in directorConf.scheduleConfigs)
|
||||||
|
{
|
||||||
|
if (locator.Calendar == CalendarSourceName)
|
||||||
|
{
|
||||||
|
if (locator.EventName.IsMatch(eventName))
|
||||||
|
{
|
||||||
|
var configurationName = locator.EventName.Replace(eventName, locator.SchedulableConfiguration);
|
||||||
|
Console.WriteLine($"found match good enough, I guess. going to load {configurationName} for {eventName}");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
handler.Handle(todo.Occurrence);
|
return JsonConvert.DeserializeObject<schedulable.Schedulable>(File.ReadAllText(configurationName));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
HumanCommunication.Instance.Say($"error in show handler! Panicking!\n{JsonConvert.SerializeObject(e)}", HumanCommunication.LogLevel.Showstopper);
|
Console.Error.WriteLine($"error btw. not sure who's not throwing one. {e.Message}");
|
||||||
}
|
return null;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//HumanCommunication.Instance.forwardToDiscord($"couldn't find suitable configuration for {eventName} within {CalendarSourceName}", HumanCommunication.LogLevel.Info);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,14 +2,14 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Schedulable;
|
using schedulable;
|
||||||
|
|
||||||
namespace director
|
namespace director
|
||||||
{
|
{
|
||||||
public class Scratch
|
public class Scratch
|
||||||
{
|
{
|
||||||
private const string path = "scratch.json";
|
private const string path = "scratch.json";
|
||||||
public List<Schedulable.Schedulable> agenda { get; set; } = new List<Schedulable.Schedulable>();
|
public List<schedulable.Scheduled> agenda { get; set; } = new List<schedulable.Scheduled>();
|
||||||
public Dictionary<string, string> Calendars { get; set; } = new Dictionary<string, string>();
|
public Dictionary<string, string> Calendars { get; set; } = new Dictionary<string, string>();
|
||||||
|
|
||||||
//calendar ICSs
|
//calendar ICSs
|
||||||
|
100
ShowHandler.cs
Normal file
100
ShowHandler.cs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Linq;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using schedulable;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace director
|
||||||
|
{
|
||||||
|
public class ShowHandler
|
||||||
|
{
|
||||||
|
private Scheduled todo;
|
||||||
|
private string outputPath;
|
||||||
|
public ShowHandler(Scheduled todo, string outputPath)
|
||||||
|
{
|
||||||
|
this.todo = todo;
|
||||||
|
this.outputPath = outputPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void StartHandling()
|
||||||
|
{
|
||||||
|
Console.WriteLine("start handling");
|
||||||
|
CreateChecklist();
|
||||||
|
var napLength = (todo.Showtime - todo.Configuration.LeadTimeDesired) - DateTime.Now;
|
||||||
|
|
||||||
|
Console.WriteLine($"napping until {todo.Showtime - todo.Configuration.LeadTimeDesired} ({napLength})");
|
||||||
|
|
||||||
|
if (napLength.TotalMinutes > 0)
|
||||||
|
{
|
||||||
|
Task.WaitAll(Task.Delay(napLength));
|
||||||
|
}
|
||||||
|
Console.WriteLine("nap done, begin the checklist. which to us effectively means SHOWTIME");
|
||||||
|
//or do I want to split the checklists in the config file? consider later.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HandleChecklist();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
HumanCommunication.Instance.Say($"error in show handler! Panicking!\n{JsonConvert.SerializeObject(e)}", HumanCommunication.LogLevel.Showstopper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateChecklist()
|
||||||
|
{
|
||||||
|
Console.WriteLine($"begin the pre-pre show by creating a checklist.");
|
||||||
|
Directory.CreateDirectory(outputPath);
|
||||||
|
var text = new StringBuilder();
|
||||||
|
text.AppendLine($"# {todo.Occurrence._event.Description}");
|
||||||
|
|
||||||
|
#region share with humans
|
||||||
|
var allItems = checklistFlattened();
|
||||||
|
if(allItems?.FirstOrDefault(pl => pl.type == "manual") != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"nothing manual, not sharing with humans.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//TODO: share
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
private IEnumerable<ProcessionLine> checklistFlattened()
|
||||||
|
{
|
||||||
|
if (todo.Configuration.checklist?.Count() > 0)
|
||||||
|
{
|
||||||
|
var toReturn = new List<ProcessionLine>();
|
||||||
|
foreach(var line in todo.Configuration.checklist)
|
||||||
|
{
|
||||||
|
toReturn.AddRange(recurseChecklist(line));
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
private IEnumerable<ProcessionLine> recurseChecklist(ProcessionLine line)
|
||||||
|
{
|
||||||
|
var asContainer = line as container;
|
||||||
|
if (asContainer == null || asContainer.subitems?.Count() == 0)
|
||||||
|
{
|
||||||
|
return new List<ProcessionLine>() { line };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var toReturn = new List<ProcessionLine>();
|
||||||
|
toReturn.AddRange(recurseChecklist(line));
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal void HandleChecklist()
|
||||||
|
{
|
||||||
|
Console.WriteLine($"should now be at the desired lead time. showtime: {todo.Showtime}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,9 +13,12 @@ namespace director
|
|||||||
private static DateTime searchStart = DateTime.Now; //is it slower to just call datetime.now every time? /shrug
|
private static DateTime searchStart = DateTime.Now; //is it slower to just call datetime.now every time? /shrug
|
||||||
private static DateTime searchEnd = DateTime.Now.AddDays(7);
|
private static DateTime searchEnd = DateTime.Now.AddDays(7);
|
||||||
public static readonly ConcurrentDictionary<string, Calendar> Calendars = new ConcurrentDictionary<string, Calendar>();
|
public static readonly ConcurrentDictionary<string, Calendar> Calendars = new ConcurrentDictionary<string, Calendar>();
|
||||||
public static void LoadCalendar(string key, string calendarString)
|
public static string LoadCalendar(string calendarString)
|
||||||
{
|
{
|
||||||
Calendars[key] = Calendar.Load(calendarString);
|
var cal = Calendar.Load(calendarString);
|
||||||
|
var key = cal.Properties["X-WR-CALNAME"].Value.ToString();
|
||||||
|
Calendars[key] = cal;
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
//I don't understand why the entire .net ecosystem insists on ignoring ToString(). Is it really that much fun writing ThingSerializerFactory? ...java programmers.
|
//I don't understand why the entire .net ecosystem insists on ignoring ToString(). Is it really that much fun writing ThingSerializerFactory? ...java programmers.
|
||||||
|
24
schedulable/Checklist.cs
Normal file
24
schedulable/Checklist.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace schedulable
|
||||||
|
{
|
||||||
|
public class ProcessionLine
|
||||||
|
{
|
||||||
|
public string description { get; set; }
|
||||||
|
public string type { get; set; } = "generic"; //TODO: experiment with $type, apparnetly newtonsoft json can use that to choose deserialization?
|
||||||
|
public ProcessionLine() { type = GetType().ToString(); }
|
||||||
|
}
|
||||||
|
public class manual : ProcessionLine { }
|
||||||
|
public class command : ProcessionLine
|
||||||
|
{
|
||||||
|
public string cmd { get; set; }
|
||||||
|
public IEnumerable<string> args { get; set; }
|
||||||
|
}
|
||||||
|
public class container : ProcessionLine
|
||||||
|
{
|
||||||
|
public IEnumerable<ProcessionLine> subitems { get; set; }
|
||||||
|
}
|
||||||
|
public class awaitShowtime : ProcessionLine { }
|
||||||
|
public class awaitCutSignal : ProcessionLine { }
|
||||||
|
}
|
@ -1,10 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Schedulable
|
|
||||||
{
|
|
||||||
//You said to echo back a message
|
|
||||||
public class MessageRelay : Schedulable
|
|
||||||
{
|
|
||||||
public silver_messages.message MessageToRelay { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using director;
|
using director;
|
||||||
|
|
||||||
namespace Schedulable
|
namespace schedulable
|
||||||
{
|
{
|
||||||
public class Schedulable
|
public class Schedulable
|
||||||
{
|
{
|
||||||
public iCalHoopJumping.CalendarOccurrence Occurrence { get; set; }
|
public TimeSpan LeadTimeDesired { get; set; }
|
||||||
public DateTime Showtime { get; set; }
|
public IEnumerable<string> AgentsNeeded { get; set; }
|
||||||
public ScedulableType ScedulableType { get; set; } = ScedulableType.Other;
|
public IEnumerable<ProcessionLine> checklist { get; set; }
|
||||||
|
// public Object conductorConfig{get;set;}
|
||||||
}
|
}
|
||||||
public enum ScedulableType { TwitchStream, YTRelease, Other };
|
|
||||||
}
|
}
|
12
schedulable/Scheduled.cs
Normal file
12
schedulable/Scheduled.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using director;
|
||||||
|
|
||||||
|
namespace schedulable
|
||||||
|
{
|
||||||
|
public class Scheduled
|
||||||
|
{
|
||||||
|
public iCalHoopJumping.CalendarOccurrence Occurrence { get; set; }
|
||||||
|
public DateTime Showtime { get; set; }
|
||||||
|
public Schedulable Configuration { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,49 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Schedulable.Show
|
|
||||||
{
|
|
||||||
public class Show
|
|
||||||
{
|
|
||||||
public PreshowTaskList PreShow { get; set; }
|
|
||||||
public TaskList PostShow { get; set; }
|
|
||||||
|
|
||||||
#region components
|
|
||||||
public class TaskList
|
|
||||||
{
|
|
||||||
public IEnumerable<Checklistable> Manual { get; set; }
|
|
||||||
public IEnumerable<CommandLine> Commands { get; set; }
|
|
||||||
}
|
|
||||||
public class PreshowTaskList : TaskList
|
|
||||||
{
|
|
||||||
public IEnumerable<string> AgentsNeeded { get; set; }
|
|
||||||
public IEnumerable<CommandLineCheck> Checks { get; set; }
|
|
||||||
}
|
|
||||||
public class Checklistable
|
|
||||||
{
|
|
||||||
//for humans
|
|
||||||
public string Label { get; set; }
|
|
||||||
public IEnumerable<Checklistable> Items { get; set; } //if no items, just throw up a checkbox
|
|
||||||
}
|
|
||||||
public class CommandLine
|
|
||||||
{
|
|
||||||
public string cmd { get; set; }
|
|
||||||
public string args { get; set; }
|
|
||||||
public TimeSpan timeout { get; set; }
|
|
||||||
public TimeSpan leadTime { get; set; }
|
|
||||||
}
|
|
||||||
public class CommandLineCheck
|
|
||||||
{
|
|
||||||
public string cmd { get; set; }
|
|
||||||
public string args { get; set; }
|
|
||||||
public string target { get; set; }
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
public class TwitchStream : Show
|
|
||||||
{
|
|
||||||
public string TwitchTitle { get; set; }
|
|
||||||
public string TwitchCategory { get; set; }
|
|
||||||
}
|
|
||||||
public class YoutubeRelease : Show { }
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
using System;
|
|
||||||
using director;
|
|
||||||
|
|
||||||
namespace ShowHandlers
|
|
||||||
{
|
|
||||||
public abstract class ShowHandler
|
|
||||||
{
|
|
||||||
public abstract void Handle(iCalHoopJumping.CalendarOccurrence evt);
|
|
||||||
public abstract TimeSpan LeadTimeDesired { get; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
using System;
|
|
||||||
using director;
|
|
||||||
|
|
||||||
namespace ShowHandlers
|
|
||||||
{
|
|
||||||
public class TwitchStreamHandler : ShowHandler
|
|
||||||
{
|
|
||||||
public override TimeSpan LeadTimeDesired => TimeSpan.FromHours(4);
|
|
||||||
|
|
||||||
public override void Handle(iCalHoopJumping.CalendarOccurrence evt)
|
|
||||||
{
|
|
||||||
Console.WriteLine("I am a twitch stream handler, it falls to me to...");
|
|
||||||
Console.WriteLine(" H A N D L E ");
|
|
||||||
Console.WriteLine($"current time is {DateTime.Now}");
|
|
||||||
}
|
|
||||||
protected void preShow_RunCommands(iCalHoopJumping.CalendarOccurrence evt)
|
|
||||||
{
|
|
||||||
// Console.WriteLine($"pre show: run commands: {string.Join(", ", PreShowCommands.Select(c => c.cmd))}");
|
|
||||||
// foreach (var cmd in PreShowCommands.OrderByDescending(cmd => cmd.leadTime))
|
|
||||||
// {
|
|
||||||
// if (DateTime.Now < evt.OccurrenceStart - cmd.leadTime)
|
|
||||||
// {
|
|
||||||
// var waitTime = evt.OccurrenceStart - cmd.leadTime - DateTime.Now;
|
|
||||||
// Console.WriteLine($"waiting {waitTime} before executing {cmd.cmd}");
|
|
||||||
// Task.WaitAll(Task.Delay(waitTime));
|
|
||||||
// }
|
|
||||||
// var argsList = new List<string>() { JsonConvert.SerializeObject(evt) }.Append(cmd.args).ToList();
|
|
||||||
|
|
||||||
// Console.WriteLine($"telefranzing execution: {cmd.cmd} with args {string.Join(' ', argsList)}");
|
|
||||||
// // Telefranz.Instance.ProduceMessage(new silver_messages.directorial.execute_command()
|
|
||||||
// // {
|
|
||||||
// // command = cmd.cmd,
|
|
||||||
// // args = argsList,
|
|
||||||
// // timeout = (int)cmd.timeout.TotalMilliseconds //TODO: update when franz gets updated
|
|
||||||
// // });
|
|
||||||
// }
|
|
||||||
// Console.WriteLine("seems all pre-show commands have been issued, but to be fair I wasn't listening for output.");
|
|
||||||
}
|
|
||||||
protected void PostShow(iCalHoopJumping.CalendarOccurrence evt)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Console.WriteLine($"post show: run commands: {string.Join(", ", config.PostShow.Commands.Select(c => c.cmd))}");
|
|
||||||
// foreach (var cmd in config.PostShow.Commands)
|
|
||||||
// {
|
|
||||||
// var argsList = new List<string>() { JsonConvert.SerializeObject(evt) }.Append(cmd.args).ToList();
|
|
||||||
|
|
||||||
// Console.WriteLine($"telefranzing execution: {cmd.cmd} with args {string.Join(' ', argsList)}");
|
|
||||||
// // Telefranz.Instance.ProduceMessage(new silver_messages.directorial.execute_command()
|
|
||||||
// // {
|
|
||||||
// // command = cmd.cmd,
|
|
||||||
// // args = argsList,
|
|
||||||
// // timeout = (int)cmd.timeout.TotalMilliseconds //TODO: update when franz gets updated
|
|
||||||
// // });
|
|
||||||
// }
|
|
||||||
// Console.WriteLine("seems all post-show commands have been issued, but to be fair I wasn't listening for output.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,125 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using director;
|
|
||||||
using Director;
|
|
||||||
using franz;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Schedulable.Show;
|
|
||||||
|
|
||||||
namespace ShowHandlers
|
|
||||||
{
|
|
||||||
public class YoutubeHandler : ShowHandler
|
|
||||||
{
|
|
||||||
private readonly AutoResetEvent checkSignal = new AutoResetEvent(false);
|
|
||||||
private static string[] AgentsNeeded { get; set; } = { "youtube" };
|
|
||||||
private List<string> agentsPresent {get;set;} = new List<string>();
|
|
||||||
public override TimeSpan LeadTimeDesired { get => TimeSpan.FromDays(1); }
|
|
||||||
private silver_messages.youtube.yt_metadata metadataSoFar = new silver_messages.youtube.yt_metadata();
|
|
||||||
|
|
||||||
public override void Handle(iCalHoopJumping.CalendarOccurrence evt)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"begin youtube handler. current time {DateTime.Now.ToLongTimeString()}");
|
|
||||||
//Console.WriteLine(JsonConvert.SerializeObject(evt));
|
|
||||||
Task.Run(() => PreShow(evt));
|
|
||||||
Console.WriteLine("kicked off the pre-show");
|
|
||||||
if (evt.OccurrenceStart > DateTime.Now)
|
|
||||||
{
|
|
||||||
Task.WaitAll(Task.Delay(evt.OccurrenceStart - DateTime.Now));
|
|
||||||
}
|
|
||||||
//youtube releases in particular jump right to post-show
|
|
||||||
PostShow(evt);
|
|
||||||
}
|
|
||||||
~YoutubeHandler()
|
|
||||||
{
|
|
||||||
//Telefranz.Instance.removeHandler<silver_messages.global.report>(agentReports);
|
|
||||||
//Telefranz.Instance.removeHandler<silver_messages.directorial.check_complete>(checkReports);
|
|
||||||
}
|
|
||||||
protected void PreShow(iCalHoopJumping.CalendarOccurrence evt)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"it's the pre-show, showtime at: {evt.OccurrenceStart}");
|
|
||||||
|
|
||||||
preShow_GetAgents(evt, TimeSpan.FromMinutes(10));
|
|
||||||
preShow_RunChecks(evt, TimeSpan.FromMinutes(10));
|
|
||||||
Console.WriteLine("pre show seems to be set.");
|
|
||||||
}
|
|
||||||
protected void preShow_GetAgents(iCalHoopJumping.CalendarOccurrence evt, TimeSpan leadNeeded)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"preshow agents needed: {string.Join(", ", AgentsNeeded)}");
|
|
||||||
agentsPresent.Clear();
|
|
||||||
|
|
||||||
Telefranz.Instance.addHandler<silver_messages.global.report>(agentReports);
|
|
||||||
Telefranz.Instance.ProduceMessage(new silver_messages.global.sound_off());
|
|
||||||
while (AgentsNeeded.Where(ap => !agentsPresent.Contains(ap))?.Count() > 0)
|
|
||||||
{
|
|
||||||
checkSignal.WaitOne(TimeSpan.FromSeconds(15));
|
|
||||||
//Telefranz.Instance.ProduceMessage(new silver_messages.global.sound_off());
|
|
||||||
if (DateTime.Now > evt.OccurrenceStart - leadNeeded)
|
|
||||||
{
|
|
||||||
var miaAgents = string.Join(", ", AgentsNeeded.Where(ap => !agentsPresent.Contains(ap)));
|
|
||||||
HumanCommunication.Instance.Say($"Youtube handler getting antsy and going forward. mia agents: {miaAgents}",
|
|
||||||
HumanCommunication.LogLevel.Warning);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
protected void preShow_RunChecks(iCalHoopJumping.CalendarOccurrence evt, TimeSpan leadNeeded)
|
|
||||||
{
|
|
||||||
var argsList = new List<string>() { JsonConvert.SerializeObject(evt) };
|
|
||||||
Telefranz.Instance.addHandler<silver_messages.youtube.metadata_needed>(youtubeAgentReports);
|
|
||||||
Console.WriteLine($"pre show: run check. It's just going to be \"is the metadata set\".");
|
|
||||||
Action issueChecks = () =>
|
|
||||||
{
|
|
||||||
//Telefranz.Instance.ProduceMessage(new silver_messages.youtube.request_metadata_needed());
|
|
||||||
};
|
|
||||||
issueChecks();
|
|
||||||
while (metadataUnset(metadataSoFar))
|
|
||||||
{
|
|
||||||
//checkSignal.WaitOne(TimeSpan.FromHours(6)); //so bother me every 6 hours before yt release time if metadata isn't ready
|
|
||||||
checkSignal.WaitOne(TimeSpan.FromSeconds(15));
|
|
||||||
if (DateTime.Now > evt.OccurrenceStart - leadNeeded)
|
|
||||||
{
|
|
||||||
HumanCommunication.Instance.Say($"Youtube handler reports no metadata in time! too late now though. {JsonConvert.SerializeObject(metadataSoFar)}",
|
|
||||||
HumanCommunication.LogLevel.Error);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
issueChecks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
protected void agentReports(silver_messages.global.report r)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"agent responding to sound off: {r.name}");
|
|
||||||
if (AgentsNeeded?.FirstOrDefault(an => an.ToLower() == r.name.ToLower()) != null)
|
|
||||||
{
|
|
||||||
lock (agentsPresent)
|
|
||||||
{
|
|
||||||
agentsPresent.Add(r.name.ToLower());
|
|
||||||
checkSignal.Set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
protected void youtubeAgentReports(silver_messages.youtube.metadata_needed neededmsg)
|
|
||||||
{
|
|
||||||
metadataSoFar = neededmsg.needed.Where(kvp => kvp.Key == "key")?.Select(kvp => kvp.Value)?.FirstOrDefault();
|
|
||||||
checkSignal.Set();
|
|
||||||
}
|
|
||||||
protected bool metadataUnset(silver_messages.youtube.yt_metadata metadata)
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
string.IsNullOrWhiteSpace(metadata.playlist)
|
|
||||||
|| metadata.recording == null
|
|
||||||
|| metadata.release == null
|
|
||||||
|| string.IsNullOrWhiteSpace(metadata.thumbnail)
|
|
||||||
|| string.IsNullOrWhiteSpace(metadata.title)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
protected void PostShow(iCalHoopJumping.CalendarOccurrence evt)
|
|
||||||
{
|
|
||||||
Console.WriteLine("there really isn't a post-show atm, but in future would be cool to pester matrix/discord/twitter");
|
|
||||||
//Telefranz.Instance.ProduceMessage(new silver_messages.directorial.execute_command("advertise"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user