draft 1
This commit is contained in:
commit
8ada6bc0ac
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
bin/
|
||||||
|
obj/
|
26
.vscode/launch.json
vendored
Normal file
26
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||||
|
// Use hover for the description of the existing attributes
|
||||||
|
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||||
|
"name": ".NET Core Launch (console)",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "build",
|
||||||
|
// If you have changed target frameworks, make sure to update the program path.
|
||||||
|
"program": "${workspaceFolder}/bin/Debug/net5.0/videoRetailor.dll",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}/sample recording sess/",
|
||||||
|
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||||
|
"console": "internalConsole",
|
||||||
|
"stopAtEntry": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": ".NET Core Attach",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "attach"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
42
.vscode/tasks.json
vendored
Normal file
42
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/videoRetailor.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "publish",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"${workspaceFolder}/videoRetailor.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "watch",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"watch",
|
||||||
|
"run",
|
||||||
|
"${workspaceFolder}/videoRetailor.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
109
Program.cs
Normal file
109
Program.cs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
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<string> path { get; set; } = new List<string>();
|
||||||
|
public List<IMediaAnalysis> ffprobed { get; set; } = new List<IMediaAnalysis>();
|
||||||
|
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<analyzedMedia>();
|
||||||
|
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
|
||||||
|
{
|
||||||
|
var afterFirst = mediaInfos.Skip(1).ToList();
|
||||||
|
foreach (var thisMeta in afterFirst)
|
||||||
|
{
|
||||||
|
totalTime += thisMeta.ffprobed[0].Duration;
|
||||||
|
}
|
||||||
|
var averageTime = totalTime.TotalSeconds / afterFirst.Count();
|
||||||
|
Console.WriteLine($"average time: {averageTime}");
|
||||||
|
foreach (var thisMeta in afterFirst)
|
||||||
|
{
|
||||||
|
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? {afterFirst.Min(af => af.durationVariance)}");
|
||||||
|
while (afterFirst.Count() > 6 &&
|
||||||
|
(afterFirst.Min(af => af.durationVariance) < 0.9))
|
||||||
|
{
|
||||||
|
Console.WriteLine("gluestick at the ready.");
|
||||||
|
var idx = 0;
|
||||||
|
var targetMinDuration = afterFirst.Min(af => af.durationVariance);
|
||||||
|
Console.WriteLine($"targetMinDuration = {targetMinDuration}");
|
||||||
|
foreach (var af in afterFirst)
|
||||||
|
{
|
||||||
|
if (af.durationVariance == targetMinDuration)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
var previousDuration = (idx == 0) ? Double.MaxValue : afterFirst[idx - 1].TotalSeconds;
|
||||||
|
var nextDuration = (idx > afterFirst.Count() - 2) ? Double.MaxValue : afterFirst[idx - 1].TotalSeconds;
|
||||||
|
analyzedMedia partner;
|
||||||
|
if (nextDuration > previousDuration)
|
||||||
|
{
|
||||||
|
partner = afterFirst[idx - 1];
|
||||||
|
Console.WriteLine($"combining with previous, previously at {partner.TotalSeconds}");
|
||||||
|
partner.ffprobed.AddRange(afterFirst[idx].ffprobed);
|
||||||
|
partner.path.AddRange(afterFirst[idx].path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
partner = afterFirst[idx + 1];
|
||||||
|
Console.WriteLine($"combining with next, previously at {partner.TotalSeconds}");
|
||||||
|
afterFirst[idx].ffprobed.AddRange(partner.ffprobed);
|
||||||
|
partner.ffprobed = afterFirst[idx].ffprobed;
|
||||||
|
afterFirst[idx].path.AddRange(partner.path);
|
||||||
|
partner.path = afterFirst[idx].path;
|
||||||
|
}
|
||||||
|
afterFirst.RemoveAt(idx);
|
||||||
|
averageTime = totalTime.TotalSeconds / afterFirst.Count();
|
||||||
|
foreach (var thisMeta in afterFirst)
|
||||||
|
{
|
||||||
|
thisMeta.durationVariance = thisMeta.TotalSeconds / averageTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mediaInfos = mediaInfos.Take(1).Union(afterFirst).ToList();
|
||||||
|
}
|
||||||
|
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}.mp4",
|
||||||
|
mi.path.ToArray()
|
||||||
|
);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
videoRetailor.csproj
Normal file
12
videoRetailor.csproj
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="ffmpegcore" Version="4.5.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
Loading…
Reference in New Issue
Block a user