Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Diagnostics;
- using System.IO;
- using System.Text.RegularExpressions;
- using System.Threading.Tasks;
- using UnityEditor;
- namespace JS
- {
- public static class Itch
- {
- public static string ButlerPath = "[YOUR BUTLER INSTALL PATH]\\butler.exe";
- public static Task PushBuildsFolder(ItchConfig config)
- {
- var builds = Path.Combine(UnityEngine.Application.dataPath, "../", "Builds");
- return Push(config, builds);
- }
- public static Task Push(ItchConfig config, string directory)
- {
- var reporter = new ItchUnityProgressReporter("Uploading to Itch:");
- return Push(directory, config.user, config.game, config.channel, reporter);
- }
- public static Task<int> Push(string directory, string user, string game, string channel,
- IProgress<ButlerProgressInfo> progress = null) =>
- ExecuteButlerAsync($"push {directory} {user}/{game}:{channel}", progress);
- static async Task<int> ExecuteButlerAsync(string arguments, IProgress<ButlerProgressInfo> progress = null,
- string workingDirectory = null)
- {
- if (arguments == null)
- throw new ArgumentNullException(nameof(arguments));
- var startInfo = new ProcessStartInfo
- {
- FileName = ButlerPath,
- Arguments = arguments,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- UseShellExecute = false,
- CreateNoWindow = true,
- WorkingDirectory = workingDirectory ?? Environment.CurrentDirectory
- };
- using var process = new Process();
- process.StartInfo = startInfo;
- process.EnableRaisingEvents = true;
- process.OutputDataReceived += (sender, e) =>
- {
- if (string.IsNullOrEmpty(e.Data)) return;
- ButlerProgressInfo progressInfo = ParseButlerOutput(e.Data);
- progress?.Report(progressInfo);
- };
- process.ErrorDataReceived += (sender, e) =>
- {
- if (!string.IsNullOrEmpty(e.Data))
- progress?.Report(new ButlerProgressInfo { Status = $"ERROR: {e.Data}", Percent = -1 });
- };
- try
- {
- process.Start();
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
- await Task.Run(() => process.WaitForExit());
- if (process.HasExited)
- {
- int exitCode = process.ExitCode;
- if (progress is ItchUnityProgressReporter rp)
- {
- if (exitCode == 0) rp.Complete();
- else rp.Fail();
- }
- if (exitCode != 0)
- throw new ButlerExecutionException($"Butler process exited with code {exitCode}");
- return exitCode;
- }
- UnityEngine.Debug.LogWarning("process did not exit within timeout");
- return -1;
- }
- catch (Exception ex)
- {
- UnityEngine.Debug.LogError($"Error executing butler: {ex.Message}");
- return -1;
- }
- }
- static ButlerProgressInfo ParseButlerOutput(string output)
- {
- ButlerProgressInfo progressInfo = new ButlerProgressInfo();
- var match = DownloadProgressRegex.Match(output);
- if (match.Success)
- {
- if (float.TryParse(match.Groups[1].Value, out float percent))
- {
- if (percent > 0)
- progressInfo.Percent = percent / 100f;
- else progressInfo.Percent = -1;
- }
- if(double.TryParse(match.Groups[3].Value, out double speed))
- {
- progressInfo.SpeedMiBs = speed;
- }
- string remainingMiBsString = match.Groups[5].Value;
- if (double.TryParse(remainingMiBsString, out double remainingMiBs)) {
- progressInfo.RemainingMiBs = remainingMiBs;
- }
- progressInfo.Status = $"Uploading - {progressInfo.Percent:F2}% @ {progressInfo.SpeedMiBs:F2} MiB/s, {progressInfo.RemainingMiBs:F2} MiB left";
- }
- else { //If no download progress, then try to extract a generic status
- var statusMatch = GenericStatusRegex.Match(output);
- if (statusMatch.Success)
- {
- progressInfo.Status = statusMatch.Groups[1].Value.Trim();
- }
- }
- return progressInfo;
- }
- public class ButlerExecutionException : Exception
- {
- public ButlerExecutionException(string message) : base(message)
- {
- }
- }
- private static readonly Regex DownloadProgressRegex = new(@"(\d+(?:\.\d+)?)%\s+@\s+((\d+(?:\.\d+)?)\s+MiB/s),\s+((\d+(?:\.\d+)?)\s+MiB) left", RegexOptions.Compiled);
- private static readonly Regex GenericStatusRegex = new(@"ÔêÖ.*?\s+(.*)", RegexOptions.Compiled);
- }
- [Serializable]
- public class ItchConfig
- {
- public string user;
- public string game;
- public string channel = "win";
- }
- [Serializable]
- public class ButlerProgressInfo
- {
- public string Status;
- public float Percent = -1;
- public double SpeedMiBs;
- public double RemainingMiBs;
- public override string ToString() => $"{Status} : {Percent} : {SpeedMiBs} : {RemainingMiBs}";
- }
- public class ItchUnityProgressReporter : IProgress<ButlerProgressInfo>
- {
- private readonly int _id;
- public ItchUnityProgressReporter(string title) => _id = Progress.Start(title);
- public void Report(ButlerProgressInfo value) => Progress.Report(_id, value.Percent, value.Status);
- public void Complete() => Progress.Finish(_id);
- public void Fail() => Progress.Finish(_id, Progress.Status.Failed);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement