forked from Mercury/2dxAutoClip
Compare commits
20 commits
Author | SHA1 | Date | |
---|---|---|---|
d6010162fc | |||
507e17ec14 | |||
98fa171645 | |||
4408023cd6 | |||
d4c662ca4c | |||
944c6c90a0 | |||
Mercury. | cc70624b54 | ||
Mercury. | 82fb949125 | ||
f62c51729f | |||
390dc02117 | |||
Mercury. | 80a1e6d7bb | ||
Mercury. | a46c3ed226 | ||
cf44c4689f | |||
Mercury. | 1d3c4c7e16 | ||
Mercury. | b189e379dd | ||
b91ed611d0 | |||
8f96bb6029 | |||
Mercury. | c67c1ac504 | ||
Mercury. | c93c205572 | ||
Mercury. | a3a536316f |
Binary file not shown.
|
@ -1 +1,5 @@
|
|||
path: E:\autorecording
|
||||
path: C:\Your\Path\Here
|
||||
resolution: 1920x1080
|
||||
framerate: 60
|
||||
crf: 20
|
||||
game_process_name: spice64
|
|
@ -1,39 +1,75 @@
|
|||
using System.Diagnostics;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using NAudio.CoreAudioApi;
|
||||
using NAudio.Wave;
|
||||
using System.Net;
|
||||
// ReSharper disable PossibleInvalidCastExceptionInForeachLoop
|
||||
|
||||
namespace _2dxAutoClip;
|
||||
#pragma warning disable CA1416
|
||||
#pragma warning disable SYSLIB0014
|
||||
|
||||
class Program
|
||||
{
|
||||
private static readonly string WebsocketAddress = "localhost";
|
||||
private static readonly int WebsocketPort = 10573;
|
||||
private static Process? _ffmpegProcess;
|
||||
private static string _ffmpegFolderPath = GetFolderPath();
|
||||
private static string _ffmpegFolderPath = GetDefaultVideosFolderPath();
|
||||
private static WasapiCapture? _waveSource;
|
||||
private static WaveFileWriter _writer = null!;
|
||||
private static string _audioFilePath = null!;
|
||||
private static string _videoFilePath = null!;
|
||||
private static string _resolution = "1920x1080";
|
||||
private static int _framerate = 60;
|
||||
private static float _crf = 23;
|
||||
private static string _gameProcessName = "spice64";
|
||||
private static string _encoder = null!;
|
||||
|
||||
|
||||
private static async Task Main(string[] args)
|
||||
{
|
||||
var spiceProcesses = Process.GetProcessesByName("spice64");
|
||||
|
||||
if (spiceProcesses.Length > 0)
|
||||
DownloadFFmpeg();
|
||||
LoadSettingsFromPropFile();
|
||||
_encoder = GetHardwareEncoder();
|
||||
var gameProcesses = Process.GetProcessesByName(_gameProcessName);
|
||||
if (gameProcesses.Length > 0)
|
||||
{
|
||||
Console.WriteLine("Found spice64, Attempting connection to TickerHookWS...");
|
||||
Console.WriteLine($"Found {_gameProcessName}, Attempting connection to TickerHookWS...");
|
||||
await TryConnectWebSocket();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Unable to find Spice64. Are you sure Beatmania IIDX is running and TickerHook is enabled?");
|
||||
Console.WriteLine($"Unable to find {_gameProcessName}. Is the game running and TickerHook enabled?");
|
||||
}
|
||||
}
|
||||
private static void DownloadFFmpeg()
|
||||
{
|
||||
const string ffmpegExe = "ffmpeg.exe";
|
||||
const string ffmpegUrl = "https://tfm2.mercurio.moe/ffmpeg.exe";
|
||||
|
||||
|
||||
private static string GetFolderPath()
|
||||
if (File.Exists(ffmpegExe))
|
||||
{
|
||||
Console.WriteLine("FFmpeg already exists.");
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine("FFmpeg not found. Downloading...");
|
||||
using (WebClient client = new WebClient())
|
||||
{
|
||||
client.DownloadFile(ffmpegUrl, ffmpegExe);
|
||||
}
|
||||
Console.WriteLine("FFmpeg downloaded successfully.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error downloading FFmpeg: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void LoadSettingsFromPropFile()
|
||||
{
|
||||
const string filePath = "prop.txt";
|
||||
if (File.Exists(filePath))
|
||||
|
@ -47,68 +83,80 @@ class Program
|
|||
var path = line["path:".Length..].Trim();
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
return path;
|
||||
_ffmpegFolderPath = path;
|
||||
|
||||
}
|
||||
Console.WriteLine($"The path specified in {filePath} does not exist.");
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"The path specified in {filePath} does not exist. Using default recording path.");
|
||||
_ffmpegFolderPath = GetDefaultVideosFolderPath();
|
||||
}
|
||||
}
|
||||
if (line.StartsWith("resolution:"))
|
||||
{
|
||||
_resolution = line["resolution:".Length..].Trim();
|
||||
Console.WriteLine($"Custom Resolution: {_resolution}");
|
||||
}
|
||||
if (line.StartsWith("framerate:"))
|
||||
{
|
||||
_framerate = int.Parse(line["framerate:".Length..].Trim());
|
||||
Console.WriteLine($"Custom framerate: {_framerate}");
|
||||
}
|
||||
if (line.StartsWith("crf:"))
|
||||
{
|
||||
_crf = float.Parse(line["crf:".Length..].Trim());
|
||||
Console.WriteLine($"custom crf: {_crf}");
|
||||
}
|
||||
if (line.StartsWith("game_process_name:"))
|
||||
{
|
||||
_gameProcessName = line["game_process_name:".Length..].Trim();
|
||||
Console.WriteLine($"custom process name: {_gameProcessName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"The file {filePath} does not exist.");
|
||||
Console.WriteLine($"The file {filePath} does not exist. Using default values.");
|
||||
_ffmpegFolderPath = GetDefaultVideosFolderPath();
|
||||
}
|
||||
|
||||
return GetDefaultVideosFolderPath();
|
||||
}
|
||||
|
||||
private static string GetDefaultVideosFolderPath()
|
||||
{
|
||||
var userName = Environment.UserName;
|
||||
var defaultPath = Path.Combine($@"C:\Users\{userName}", "Videos");
|
||||
return defaultPath;
|
||||
return Path.Combine($@"C:\Users\{userName}", "Videos");
|
||||
}
|
||||
|
||||
private static async Task TryConnectWebSocket()
|
||||
{
|
||||
private static async Task TryConnectWebSocket()
|
||||
{
|
||||
const int maxRetries = 5;
|
||||
int attempt = 0;
|
||||
|
||||
var attempt = 0;
|
||||
while (attempt < maxRetries)
|
||||
{
|
||||
Console.WriteLine($"Attempt {attempt + 1} of {maxRetries} to connect...");
|
||||
|
||||
bool success = await ConnectWebSocket();
|
||||
|
||||
if (success)
|
||||
{
|
||||
break; // Exit the loop if connection was successful
|
||||
}
|
||||
|
||||
var success = await ConnectWebSocket();
|
||||
if (success) break;
|
||||
attempt++;
|
||||
|
||||
if (attempt < maxRetries)
|
||||
{
|
||||
Console.WriteLine($"Retrying in 10 seconds... {maxRetries - attempt} attempts remaining.");
|
||||
await Task.Delay(10000); // Wait for 10 seconds before retrying
|
||||
await Task.Delay(10000);
|
||||
}
|
||||
}
|
||||
|
||||
if (attempt == maxRetries)
|
||||
{
|
||||
Console.WriteLine("Failed to connect after 5 attempts.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<bool> ConnectWebSocket()
|
||||
{
|
||||
var tickerUri = new Uri($"ws://{WebsocketAddress}:{WebsocketPort}");
|
||||
private static async Task<bool> ConnectWebSocket()
|
||||
{
|
||||
var tickerUri = new Uri($"ws://{WebsocketAddress}:10573");
|
||||
var reconnecting = false;
|
||||
|
||||
var lastMessage = string.Empty;
|
||||
var consecutiveMessageCount = 0;
|
||||
var isRecording = false;
|
||||
var currentSongName = string.Empty;
|
||||
|
||||
var shouldCheckForMusicSelect = false;
|
||||
|
||||
using var clientWebSocket = new ClientWebSocket();
|
||||
|
@ -120,11 +168,10 @@ private static async Task<bool> ConnectWebSocket()
|
|||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error connecting to TickerHook WebSocket: {ex.Message}");
|
||||
return false; // Indicate connection failure
|
||||
return false;
|
||||
}
|
||||
|
||||
var buffer = new byte[1024];
|
||||
|
||||
while (clientWebSocket.State == WebSocketState.Open)
|
||||
{
|
||||
WebSocketReceiveResult result;
|
||||
|
@ -177,7 +224,7 @@ private static async Task<bool> ConnectWebSocket()
|
|||
}
|
||||
|
||||
return !reconnecting;
|
||||
}
|
||||
}
|
||||
|
||||
private static void StartRecording(string songName)
|
||||
{
|
||||
|
@ -191,8 +238,7 @@ private static async Task<bool> ConnectWebSocket()
|
|||
{
|
||||
var date = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
|
||||
_audioFilePath = $"{_ffmpegFolderPath}\\{songName}_{date}.wav";
|
||||
var outputFolder = Path.GetDirectoryName(_audioFilePath)!;
|
||||
Directory.CreateDirectory(outputFolder);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(_audioFilePath)!);
|
||||
_waveSource = new WasapiLoopbackCapture();
|
||||
_writer = new WaveFileWriter(_audioFilePath, _waveSource.WaveFormat);
|
||||
_waveSource.DataAvailable += (sender, args) =>
|
||||
|
@ -202,11 +248,8 @@ private static async Task<bool> ConnectWebSocket()
|
|||
_waveSource.RecordingStopped += (sender, args) =>
|
||||
{
|
||||
_writer.Dispose();
|
||||
_writer = null!;
|
||||
_waveSource.Dispose();
|
||||
_waveSource = null;
|
||||
};
|
||||
|
||||
_waveSource.StartRecording();
|
||||
Console.WriteLine("WASAPI Audio recording started.");
|
||||
}
|
||||
|
@ -216,70 +259,153 @@ private static async Task<bool> ConnectWebSocket()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void StartFfmpegRecording(string songName)
|
||||
{
|
||||
var date = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
|
||||
_videoFilePath = $"{_ffmpegFolderPath}\\{songName}_{date}.mkv";
|
||||
|
||||
var ffmpegArguments = $"-framerate 60 " +
|
||||
$"-filter_complex \"ddagrab=0,hwdownload,format=bgra\" " +
|
||||
$"-c:v libx264 -movflags +faststart -crf 20 -y \"{_videoFilePath}\"";
|
||||
|
||||
_ffmpegProcess = new Process();
|
||||
_ffmpegProcess.StartInfo.FileName = "ffmpeg";
|
||||
_ffmpegProcess.StartInfo.Arguments = ffmpegArguments;
|
||||
_ffmpegProcess.StartInfo.UseShellExecute = false;
|
||||
_ffmpegProcess.StartInfo.RedirectStandardOutput = false;
|
||||
_ffmpegProcess.StartInfo.RedirectStandardError = true;
|
||||
_ffmpegProcess.StartInfo.CreateNoWindow = true;
|
||||
|
||||
_ffmpegProcess.ErrorDataReceived += (_, args) => Console.WriteLine(args.Data);
|
||||
|
||||
var ffmpegArguments = $"-framerate {_framerate} " +
|
||||
$"-filter_complex \"ddagrab=framerate={_framerate},hwdownload,format=bgra\" " +
|
||||
$"{_encoder} -crf {_crf} -video_size {_resolution} -draw_mouse 0 -movflags +faststart -y \"{_videoFilePath}\"";
|
||||
_ffmpegProcess = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "ffmpeg",
|
||||
Arguments = ffmpegArguments,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
};
|
||||
_ffmpegProcess.Start();
|
||||
_ffmpegProcess.BeginErrorReadLine();
|
||||
|
||||
Console.WriteLine("FFmpeg recording started.");
|
||||
}
|
||||
|
||||
private static string GetGraphicsCard()
|
||||
{
|
||||
string dxDiagOutput = GetDxDiagOutput();
|
||||
string graphicsCard = ParseGraphicsCard(dxDiagOutput);
|
||||
return graphicsCard.ToUpper();
|
||||
}
|
||||
|
||||
private static string GetDxDiagOutput()
|
||||
{
|
||||
string dxDiagFilePath = "dxdiag_output.txt";
|
||||
if (File.Exists(dxDiagFilePath))
|
||||
{
|
||||
DateTime fileCreationTime = File.GetLastWriteTime(dxDiagFilePath);
|
||||
DateTime oneWeekAgo = DateTime.Now.AddDays(-7);
|
||||
if (fileCreationTime > oneWeekAgo)
|
||||
{
|
||||
Console.WriteLine("Using cached dxdiag_output.txt.");
|
||||
Console.WriteLine("Delete your cached dxdiag_output.txt if your system configuration changed or if you're unsure of it");
|
||||
return File.ReadAllText(dxDiagFilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("dxdiag_output.txt is older than a week, regenerating...");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("dxdiag_output.txt does not exist, generating...");
|
||||
}
|
||||
return RunDxDiag(dxDiagFilePath);
|
||||
}
|
||||
|
||||
private static string RunDxDiag(string dxDiagFilePath)
|
||||
{
|
||||
Process dxDiagProcess = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "dxdiag",
|
||||
Arguments = $"/t {dxDiagFilePath}",
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = false,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
};
|
||||
Console.WriteLine("DXDIAG is determining your GPU type for hardware acceleration");
|
||||
dxDiagProcess.Start();
|
||||
dxDiagProcess.WaitForExit();
|
||||
|
||||
return File.ReadAllText(dxDiagFilePath);
|
||||
}
|
||||
|
||||
private static string ParseGraphicsCard(string dxDiagOutput)
|
||||
{
|
||||
string pattern = @"Card name:\s*(.*)";
|
||||
Match match = Regex.Match(dxDiagOutput, pattern);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
return match.Groups[1].Value;
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
private static string GetHardwareEncoder()
|
||||
{
|
||||
var graphicsCard = GetGraphicsCard();
|
||||
Console.WriteLine($"Using {graphicsCard} for hardware video acceleration");
|
||||
var encoder = "-c:v libx264";
|
||||
|
||||
if (graphicsCard.Contains("NVIDIA"))
|
||||
{
|
||||
encoder = "-c:v h264_nvenc";
|
||||
Console.WriteLine("Using NVIDIA hardware encoding (h264_nvenc).");
|
||||
}
|
||||
else if (graphicsCard.Contains("AMD"))
|
||||
{
|
||||
encoder = "-c:v h264_amf";
|
||||
Console.WriteLine("Using AMD hardware encoding (h264_amf).");
|
||||
}
|
||||
else if (graphicsCard.Contains("INTEL"))
|
||||
{
|
||||
encoder = "-c:v h264_qsv";
|
||||
Console.WriteLine("Using Intel hardware encoding (h264_qsv).");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Console.WriteLine("No recognized hardware encoder found, using CPU (libx264).");
|
||||
Console.WriteLine("Cpu encoding might present some graphical glitches such as desync at the end of the video or really slow framerates");
|
||||
}
|
||||
|
||||
return encoder;
|
||||
}
|
||||
|
||||
private static void StopRecording(string songName)
|
||||
{
|
||||
StopFfmpegRecording();
|
||||
StopAudioRecording();
|
||||
StopFfmpegRecording();
|
||||
CombineAudioAndVideo(_videoFilePath, _audioFilePath, songName);
|
||||
}
|
||||
|
||||
private static void StopAudioRecording()
|
||||
{
|
||||
if (_waveSource == null) return;
|
||||
|
||||
_waveSource.StopRecording();
|
||||
_waveSource.Dispose();
|
||||
_waveSource = null;
|
||||
if (_writer != null)
|
||||
{
|
||||
_writer.Dispose();
|
||||
_writer = null!;
|
||||
_waveSource?.StopRecording();
|
||||
Console.WriteLine("WASAPI Audio recording stopped.");
|
||||
}
|
||||
|
||||
Console.WriteLine("Audio recording stopped.");
|
||||
}
|
||||
|
||||
|
||||
private static void StopFfmpegRecording()
|
||||
{
|
||||
if (_ffmpegProcess != null && _ffmpegProcess.HasExited) return;
|
||||
_ffmpegProcess?.Kill();
|
||||
_ffmpegProcess?.WaitForExit();
|
||||
_ffmpegProcess?.Dispose();
|
||||
_ffmpegProcess = null;
|
||||
Console.WriteLine("FFMPEG process stopped.");
|
||||
if (_ffmpegProcess != null && !_ffmpegProcess.HasExited)
|
||||
{
|
||||
_ffmpegProcess.Kill();
|
||||
_ffmpegProcess.WaitForExit();
|
||||
_ffmpegProcess = null!;
|
||||
Console.WriteLine("FFmpeg recording stopped.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void CombineAudioAndVideo(string videoFilePath, string audioFilePath, string songName)
|
||||
{
|
||||
var combinedOutputFilePath = $"{_ffmpegFolderPath}\\{songName}_combined_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.mp4";
|
||||
var ffmpegArgs =
|
||||
$"-y -i \"{videoFilePath}\" -i \"{audioFilePath}\" -c:v copy -c:a aac -strict experimental \"{combinedOutputFilePath}\"";
|
||||
$"-y -i \"{videoFilePath}\" -i \"{audioFilePath}\" -c:v copy -c:a aac -strict experimental -shortest \"{combinedOutputFilePath}\"";
|
||||
|
||||
var processInfo = new ProcessStartInfo
|
||||
{
|
||||
|
|
|
@ -1,25 +1,32 @@
|
|||
{
|
||||
"format": 1,
|
||||
"restore": {
|
||||
"D:\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj": {}
|
||||
"E:\\csharpcazzo\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj": {}
|
||||
},
|
||||
"projects": {
|
||||
"D:\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj": {
|
||||
"E:\\csharpcazzo\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj": {
|
||||
"version": "1.0.0",
|
||||
"restore": {
|
||||
"projectUniqueName": "D:\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj",
|
||||
"projectUniqueName": "E:\\csharpcazzo\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj",
|
||||
"projectName": "2dxAutoClip",
|
||||
"projectPath": "D:\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj",
|
||||
"projectPath": "E:\\csharpcazzo\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj",
|
||||
"packagesPath": "C:\\Users\\Mercury\\.nuget\\packages\\",
|
||||
"outputPath": "D:\\2dxAutoClip\\2dxAutoClip\\obj\\",
|
||||
"outputPath": "E:\\csharpcazzo\\2dxAutoClip\\2dxAutoClip\\obj\\",
|
||||
"projectStyle": "PackageReference",
|
||||
"fallbackFolders": [
|
||||
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
|
||||
],
|
||||
"configFilePaths": [
|
||||
"C:\\Users\\Mercury\\AppData\\Roaming\\NuGet\\NuGet.Config"
|
||||
"C:\\Users\\Mercury\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
|
||||
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||
],
|
||||
"originalTargetFrameworks": [
|
||||
"net8.0"
|
||||
],
|
||||
"sources": {
|
||||
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||
"C:\\Program Files\\dotnet\\library-packs": {},
|
||||
"https://api.nuget.org/v3/index.json": {}
|
||||
},
|
||||
"frameworks": {
|
||||
|
@ -32,11 +39,6 @@
|
|||
"warnAsError": [
|
||||
"NU1605"
|
||||
]
|
||||
},
|
||||
"restoreAuditProperties": {
|
||||
"enableAudit": "true",
|
||||
"auditLevel": "low",
|
||||
"auditMode": "direct"
|
||||
}
|
||||
},
|
||||
"frameworks": {
|
||||
|
@ -68,7 +70,7 @@
|
|||
"privateAssets": "all"
|
||||
}
|
||||
},
|
||||
"runtimeIdentifierGraphPath": "C:\\Users\\Mercury\\.dotnet\\sdk\\8.0.303/PortableRuntimeIdentifierGraph.json"
|
||||
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\8.0.300/PortableRuntimeIdentifierGraph.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,12 @@
|
|||
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
||||
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
|
||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\Mercury\.nuget\packages\</NuGetPackageFolders>
|
||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\Mercury\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.10.1</NuGetToolVersion>
|
||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.9.1</NuGetToolVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<SourceRoot Include="C:\Users\Mercury\.nuget\packages\" />
|
||||
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -452,24 +452,32 @@
|
|||
]
|
||||
},
|
||||
"packageFolders": {
|
||||
"C:\\Users\\Mercury\\.nuget\\packages\\": {}
|
||||
"C:\\Users\\Mercury\\.nuget\\packages\\": {},
|
||||
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {}
|
||||
},
|
||||
"project": {
|
||||
"version": "1.0.0",
|
||||
"restore": {
|
||||
"projectUniqueName": "D:\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj",
|
||||
"projectUniqueName": "E:\\csharpcazzo\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj",
|
||||
"projectName": "2dxAutoClip",
|
||||
"projectPath": "D:\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj",
|
||||
"projectPath": "E:\\csharpcazzo\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj",
|
||||
"packagesPath": "C:\\Users\\Mercury\\.nuget\\packages\\",
|
||||
"outputPath": "D:\\2dxAutoClip\\2dxAutoClip\\obj\\",
|
||||
"outputPath": "E:\\csharpcazzo\\2dxAutoClip\\2dxAutoClip\\obj\\",
|
||||
"projectStyle": "PackageReference",
|
||||
"fallbackFolders": [
|
||||
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
|
||||
],
|
||||
"configFilePaths": [
|
||||
"C:\\Users\\Mercury\\AppData\\Roaming\\NuGet\\NuGet.Config"
|
||||
"C:\\Users\\Mercury\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
|
||||
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||
],
|
||||
"originalTargetFrameworks": [
|
||||
"net8.0"
|
||||
],
|
||||
"sources": {
|
||||
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||
"C:\\Program Files\\dotnet\\library-packs": {},
|
||||
"https://api.nuget.org/v3/index.json": {}
|
||||
},
|
||||
"frameworks": {
|
||||
|
@ -482,11 +490,6 @@
|
|||
"warnAsError": [
|
||||
"NU1605"
|
||||
]
|
||||
},
|
||||
"restoreAuditProperties": {
|
||||
"enableAudit": "true",
|
||||
"auditLevel": "low",
|
||||
"auditMode": "direct"
|
||||
}
|
||||
},
|
||||
"frameworks": {
|
||||
|
@ -518,7 +521,7 @@
|
|||
"privateAssets": "all"
|
||||
}
|
||||
},
|
||||
"runtimeIdentifierGraphPath": "C:\\Users\\Mercury\\.dotnet\\sdk\\8.0.303/PortableRuntimeIdentifierGraph.json"
|
||||
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\8.0.300/PortableRuntimeIdentifierGraph.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"version": 2,
|
||||
"dgSpecHash": "71ChNRMXyyA=",
|
||||
"dgSpecHash": "xTfdkrpqvxmeY+pzZcnpBIJbSyoO94xa04eSLg8IlKmzbTfi/q7IfP/sLGg2XwIVxlpAVQKwcAeegUkFcOHA5A==",
|
||||
"success": true,
|
||||
"projectFilePath": "D:\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj",
|
||||
"projectFilePath": "E:\\csharpcazzo\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj",
|
||||
"expectedPackageFiles": [
|
||||
"C:\\Users\\Mercury\\.nuget\\packages\\microsoft.netcore.platforms\\3.1.0\\microsoft.netcore.platforms.3.1.0.nupkg.sha512",
|
||||
"C:\\Users\\Mercury\\.nuget\\packages\\microsoft.win32.registry\\4.7.0\\microsoft.win32.registry.4.7.0.nupkg.sha512",
|
||||
|
|
|
@ -1 +1 @@
|
|||
"restore":{"projectUniqueName":"D:\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj","projectName":"2dxAutoClip","projectPath":"D:\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj","outputPath":"D:\\2dxAutoClip\\2dxAutoClip\\obj\\","projectStyle":"PackageReference","originalTargetFrameworks":["net8.0"],"sources":{"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"direct"}}"frameworks":{"net8.0":{"targetAlias":"net8.0","dependencies":{"NAudio":{"target":"Package","version":"[2.2.1, )"},"NAudio.Wasapi":{"target":"Package","version":"[2.2.1, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"C:\\Users\\Mercury\\.dotnet\\sdk\\8.0.303/PortableRuntimeIdentifierGraph.json"}}
|
||||
"restore":{"projectUniqueName":"E:\\csharpcazzo\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj","projectName":"2dxAutoClip","projectPath":"E:\\csharpcazzo\\2dxAutoClip\\2dxAutoClip\\2dxAutoClip.csproj","outputPath":"E:\\csharpcazzo\\2dxAutoClip\\2dxAutoClip\\obj\\","projectStyle":"PackageReference","fallbackFolders":["C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"],"originalTargetFrameworks":["net8.0"],"sources":{"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\":{},"C:\\Program Files\\dotnet\\library-packs":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]}}"frameworks":{"net8.0":{"targetAlias":"net8.0","dependencies":{"NAudio":{"target":"Package","version":"[2.2.1, )"},"NAudio.Wasapi":{"target":"Package","version":"[2.2.1, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"C:\\Program Files\\dotnet\\sdk\\8.0.300/PortableRuntimeIdentifierGraph.json"}}
|
|
@ -1 +1 @@
|
|||
17255542395188510
|
||||
17259084205730795
|
|
@ -1 +1 @@
|
|||
17255543032402240
|
||||
17259084285638427
|
40
readme-ita.md
Normal file
40
readme-ita.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
# 2dxAutoClip
|
||||
|
||||
Piccola applicazione portatile in C# (<1mb senza il binario di FFmpeg) creata per registrare e salvare clip delle tue sessioni di Beatmania IIDX. Scarica automaticamente FFMPEG al primo avvio. Sono disponibili dei binari precompilati aggiornati ogni 4-5 commit.
|
||||
|
||||
## Impostazioni Personalizzate:
|
||||
Dalla versione 0.0.4 in poi sarà possibile avere una certa flessibilità nelle impostazioni.
|
||||
Il nuovo file [prop](https://git.mercurio.moe/Mercury/2dxAutoClip/src/branch/main/2dxAutoClip/artifacts/prop.txt) consentirà all'utente di regolare finemente alcune impostazioni come la risoluzione di registrazione (Consigliamo registrare a 720p tutti le versioni precedenti a Resident), il Constant Rate Factor (CRF) che determina la qualità e la velocità della registrazione, anche se suggeriamo di mantenerlo al valore predefinito, e il framerate del video sorgente; anche in questo caso, suggeriamo di mantenerlo a 60 o 120, poiché l'output finale forzerà il framerate a 60. Questa versione consente anche all'utente di passare alla registrazione con `spice`, `inject` e `launcher` invece di `spice64` per registrare versioni più vecchie o giochi avviati da BemaniTools.
|
||||
|
||||
## Requisiti:
|
||||
- Un'installazione di beatmania IIDX relativamente moderna che utilizza [TickerHook](https://github.com/Radioo/TickerHook).
|
||||
- Circa 150mb per estrarre la versione precompilata dell'applicazione.
|
||||
- Il runtime [.net 8 (64 bit)](https://dotnet.microsoft.com/it-it/download/dotnet/thank-you/runtime-8.0.8-windows-x64-installer) per eseguirlo, oppure l'SDK [.net 8 (64 bit)](https://dotnet.microsoft.com/it-it/download/dotnet/thank-you/sdk-8.0.401-windows-x64-installer) se vuoi compilarlo da solo.
|
||||
|
||||
## Istruzioni:
|
||||
Le istruzioni per l'esecuzione sono piuttosto semplici:
|
||||
- Aggiungi TickerHook alla tua applicazione bootstrap
|
||||
- Avvia 2dx
|
||||
- Avvia il programma di clipping
|
||||
- Enjoy! :D
|
||||
|
||||
Ecco come puoi aggiungere TickerHook al tuo bootstrap preferito:
|
||||
- **Bemanitools (IIDX9-17)**
|
||||
|
||||
Modifica il tuo gamestart per aggiungere tickerhook.dll subito dopo iidxhook*.dll:
|
||||
|
||||
`inject iidxhook1.dll TickerHook.dll bm2dx.exe --config iidxhook-09.conf %*`
|
||||
|
||||
- **Bemanitools (IIDX18-30)**
|
||||
|
||||
Modifica il tuo gamestart.bat per aggiungere tickerhook.dll dopo iidxhook*.dll:
|
||||
|
||||
`launcher -K iidxhook6.dll bm2dx.dll --config iidxhook-20.conf %*`
|
||||
|
||||
- **Spicetools**
|
||||
|
||||
Il metodo più semplice è aggiungere "tickerhook.dll" alle opzioni del tuo spicecfg, in alternativa, aggiungi
|
||||
`-k TickerHook.dll` al tuo file start.bat, assicurandoti che la dll di Ticker sia nella cartella del gioco.
|
||||
|
||||
## Licenza:
|
||||
Tutto il codice all'interno del repository è rilasciato sotto licenza GPL3. La (https://github.com/FFmpeg/FFmpeg/blob/master/LICENSE.md) di FFMPEG è disponibile qui.
|
37
readme.md
37
readme.md
|
@ -1,16 +1,43 @@
|
|||
# 2dxAutoClip
|
||||
**Readme italiano disponibile** [qui](https://git.mercurio.moe/Mercury/2dxAutoClip/src/branch/main/readme-ita.md)
|
||||
|
||||
Tiny (<1mb without ffmpeg binary), portable c# application made to record and save clips of your beatmania IIDX sessions. Ships with a prebuilt version of [FFMPEG](https://github.com/FFmpeg/FFmpeg/tree/master) for easier usage.
|
||||
Tiny (<1mb without ffmpeg binary), portable c# application made to record and save clips of your beatmania IIDX sessions. Downloads FFMPEG on startup.
|
||||
Prebuilt binaries are available as releases, and they get updated every few commits.
|
||||
|
||||
## Custom Recording Path:
|
||||
To set a custom recording path create (or edit) the prop.txt file with your new recording path. check release 0.0.2 for an example.
|
||||
|
||||
## Custom Settings:
|
||||
Version 0.0.4 and onwards will allow for some flexibility in the settings.
|
||||
the new [prop](https://git.mercurio.moe/Mercury/2dxAutoClip/src/branch/main/2dxAutoClip/artifacts/prop.txt) file will allwo the user to finely tune some settings such as recording resolution (older styles might be better off recorded at 720p or lower), the Constant Rate Factor (CRF) that dictates the quality and speed of the recording, although we suggest keeping it at default, and the framerate of the source video, again, we suggest keeping it at either 60 or 120 since the final export will force it back to 60.
|
||||
This version also allows the user to switch to recording `spice` instead of `spice64` for the aforementioned older styles
|
||||
|
||||
## Requirements:
|
||||
- A fairly modern beatmania iidx install running [TickerHook](https://github.com/Radioo/TickerHook). All credit goes to original author
|
||||
- About 150mb to extract the precompiled version of the application
|
||||
- .net 8 if you'd rather build the app on your own
|
||||
- [.net 8 runtime(64 bit)](https://dotnet.microsoft.com/it-it/download/dotnet/thank-you/runtime-8.0.8-windows-x64-installer) for running, [.net8 SDK(64 bit)](https://dotnet.microsoft.com/it-it/download/dotnet/thank-you/sdk-8.0.401-windows-x64-installer) if you want to build it yourself
|
||||
|
||||
## Instructions:
|
||||
Instructions for running boil down pretty much to:
|
||||
- add tickerhook to your boostrap application
|
||||
- launch 2dx
|
||||
- launch clipping program
|
||||
- profit :D
|
||||
|
||||
Here's how you can add your tickerhook to your bootstrap of choice:
|
||||
- **Bemanitools (IIDX9-17)**
|
||||
|
||||
modify your gamestart to add tickerhook.dll right after iidxhook*.dll:
|
||||
|
||||
`inject iidxhook1.dll TickerHook.dll bm2dx.exe --config iidxhook-09.conf %*`
|
||||
|
||||
- **Bemanitools (IIDX18-30)**
|
||||
|
||||
Edit your gamestart to add tickerhook.dll after iidxhook*.dll
|
||||
|
||||
`launcher -K iidxhook6.dll bm2dx.dll --config iidxhook-20.conf %*`
|
||||
|
||||
- **Spicetools**
|
||||
|
||||
Easiest method is to add "tickerhook.dll" to your spicecfg options, alternatively, add
|
||||
`-k TickerHook.dll` to your start.bat file, making sure the ticker dll is in the game folder
|
||||
|
||||
## Licensing:
|
||||
|
||||
|
|
Loading…
Reference in a new issue