using System; using System.Linq; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using FFMpegCore; namespace videoRetailor { public class analyzedMedia { public List path { get; set; } = new List(); public List ffprobed { get; set; } = new List(); public double TotalSeconds { get { return ffprobed.Sum(ima => ima.Duration.TotalSeconds); } } public double durationVariance { get; set; } } class Program { static async Task Main(string[] args) { Console.WriteLine(Directory.GetCurrentDirectory()); var mkvFiles = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.mkv"); var mediaInfos = new List(); var totalTime = new TimeSpan(); foreach (var file in mkvFiles.OrderBy(f => f)) { var thisMeta = new analyzedMedia(); thisMeta.path.Add(file); thisMeta.ffprobed.Add(await FFProbe.AnalyseAsync(file)); mediaInfos.Add(thisMeta); } if (mediaInfos.Count < 8) { Console.WriteLine($"there's only {mkvFiles.Length}, can't recombine. just going to send them all as-is."); } else { foreach (var thisMeta in mediaInfos) { totalTime += thisMeta.ffprobed[0].Duration; } var averageTime = totalTime.TotalSeconds / mediaInfos.Count(); Console.WriteLine($"average time: {averageTime}"); foreach (var thisMeta in mediaInfos) { thisMeta.durationVariance = thisMeta.TotalSeconds / averageTime; Console.WriteLine($"{string.Join(", ", thisMeta.path)}: {thisMeta.TotalSeconds} seconds"); Console.WriteLine($" duration ratio: {thisMeta.durationVariance}"); } Console.WriteLine($"...am I crashing? {mediaInfos.Min(af => af.durationVariance)}"); while (mediaInfos.Count() > 7 && (mediaInfos.Min(af => af.durationVariance) < 0.9)) { Console.WriteLine("gluestick at the ready."); var idx = 0; var targetMinDuration = mediaInfos.Min(af => af.durationVariance); Console.WriteLine($"targetMinDuration = {targetMinDuration}"); foreach (var af in mediaInfos) { if (af.durationVariance == targetMinDuration) { break; } idx++; } var previousDuration = (idx == 0) ? Double.MaxValue : mediaInfos[idx - 1].TotalSeconds; var nextDuration = (idx > mediaInfos.Count() - 2) ? Double.MaxValue : mediaInfos[idx - 1].TotalSeconds; analyzedMedia partner; if (nextDuration > previousDuration) { partner = mediaInfos[idx - 1]; Console.WriteLine($"combining with previous, previously at {partner.TotalSeconds}"); partner.ffprobed.AddRange(mediaInfos[idx].ffprobed); partner.path.AddRange(mediaInfos[idx].path); } else { partner = mediaInfos[idx + 1]; Console.WriteLine($"combining with next, previously at {partner.TotalSeconds}"); mediaInfos[idx].ffprobed.AddRange(partner.ffprobed); partner.ffprobed = mediaInfos[idx].ffprobed; mediaInfos[idx].path.AddRange(partner.path); partner.path = mediaInfos[idx].path; } mediaInfos.RemoveAt(idx); averageTime = totalTime.TotalSeconds / mediaInfos.Count(); foreach (var thisMeta in mediaInfos) { thisMeta.durationVariance = thisMeta.TotalSeconds / averageTime; } } } Console.WriteLine($"{mediaInfos.Count()} infos."); var i = 1; foreach (var mi in mediaInfos) { Console.WriteLine($"going to export {string.Join(", ", mi.path)} as part {i}"); FFMpeg.Join($"./{DateTime.Today.ToShortDateString()} (part {i}/{mediaInfos.Count()}).mp4", mi.path.ToArray() ); i++; } } } }