diff --git a/MetaforceInstaller.Cli/MetaforceInstaller.Cli.csproj b/MetaforceInstaller.Cli/MetaforceInstaller.Cli.csproj deleted file mode 100644 index a267acc..0000000 --- a/MetaforceInstaller.Cli/MetaforceInstaller.Cli.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - Exe - net8.0 - enable - true - true - enable - - - - - - - - - - - - - - - diff --git a/MetaforceInstaller.Cli/Program.cs b/MetaforceInstaller.Cli/Program.cs deleted file mode 100644 index bf8bf51..0000000 --- a/MetaforceInstaller.Cli/Program.cs +++ /dev/null @@ -1,133 +0,0 @@ -using MetaforceInstaller.Cli.Utils; -using MetaforceInstaller.Core.Services; - -namespace MetaforceInstaller.Cli; - -static class Program -{ - static async Task Main(string[] args) - { - try - { - var installationRequest = ArgumentParser.ParseArguments(args); - - if (installationRequest is null || - string.IsNullOrEmpty(installationRequest.ApkPath) || - string.IsNullOrEmpty(installationRequest.ZipPath)) - { - ShowUsage(); - return; - } - - var adbService = new AdbService(); - - var apkInfo = ApkScrapper.GetApkInfo(installationRequest.ApkPath); - var zipName = Path.GetFileName(installationRequest.ZipPath); - var outputPath = - @$"/storage/emulated/0/Android/data/{apkInfo.PackageName}/files/{zipName}"; - - // Подписка на события прогресса - adbService.ProgressChanged += OnProgressChanged; - adbService.StatusChanged += OnStatusChanged; - - // Получение информации об устройстве - var deviceInfo = adbService.GetDeviceInfo(); - Console.WriteLine($"Найдено устройство: {deviceInfo.SerialNumber}"); - Console.WriteLine($"Состояние: {deviceInfo.State}"); - Console.WriteLine($"Модель: {deviceInfo.Model} - {deviceInfo.Name}"); - Console.WriteLine(); - - // Создание объекта для отслеживания прогресса - var progress = new Progress(OnProgressReport); - - // Установка APK - await adbService.InstallApkAsync(installationRequest.ApkPath, progress); - Console.WriteLine(); - - // Копирование файла - await adbService.CopyFileAsync(installationRequest.ZipPath, outputPath, progress); - Console.WriteLine(); - - Console.WriteLine("Операция завершена успешно!"); - } - catch (Exception ex) - { - Console.WriteLine($"Ошибка: {ex.Message}"); - } - } - - private static void OnProgressChanged(object? sender, MetaforceInstaller.Core.Models.ProgressInfo e) - { - DrawProgressBar(e.PercentageComplete, e.BytesTransferred, e.TotalBytes); - } - - private static void OnStatusChanged(object? sender, string e) - { - Console.WriteLine(e); - } - - private static void OnProgressReport(MetaforceInstaller.Core.Models.ProgressInfo progressInfo) - { - if (progressInfo.TotalBytes > 0) - { - DrawProgressBar(progressInfo.PercentageComplete, progressInfo.BytesTransferred, progressInfo.TotalBytes); - } - else - { - // Для случаев без информации о байтах (например, установка APK) - DrawProgressBar(progressInfo.PercentageComplete, 0, 100); - } - } - - static void ShowUsage() - { - Console.WriteLine("Использование:"); - Console.WriteLine( - " MetaforceInstaller.exe --apk <путь_к_apk> --content <путь_к_zip> --output <путь_для контента>"); - Console.WriteLine(" MetaforceInstaller.exe -a <путь_к_apk> -c <путь_к_zip> -o <путь_для_контента>"); - Console.WriteLine(); - Console.WriteLine("Параметры:"); - Console.WriteLine(" --apk, -a Путь к APK файлу"); - Console.WriteLine(" --content, -c Путь к ZIP файлу с контентом"); - Console.WriteLine(" --output, -o Путь для копирования контента"); - Console.WriteLine(" --help, -h Показать эту справку"); - Console.WriteLine(); - Console.WriteLine("Пример:"); - Console.WriteLine( - " MetaforceInstaller.exe --apk \"C:\\app.apk\" --content \"C:\\data.zip\" --output \"/sdcard/data.zip\""); - Console.WriteLine(" MetaforceInstaller.exe -a app.apk -c data.zip -o /sdcard/data.zip"); - } - - private static void DrawProgressBar(int progress, long receivedBytes, long totalBytes) - { - Console.SetCursorPosition(0, Console.CursorTop); - - var barLength = 40; - var filledLength = (int)(barLength * progress / 100.0); - - var bar = "[" + new string('█', filledLength) + new string('░', barLength - filledLength) + "]"; - - string bytesText = ""; - if (totalBytes > 0) - { - bytesText = $" {FormatBytes(receivedBytes)} / {FormatBytes(totalBytes)}"; - } - - Console.Write($"\r{bar} {progress}%{bytesText}"); - } - - private static string FormatBytes(long bytes) - { - string[] suffixes = ["B", "KB", "MB", "GB", "TB"]; - var counter = 0; - double number = bytes; - - while (Math.Round(number / 1024) >= 1) - { - number /= 1024; - counter++; - } - - return $"{number:N1} {suffixes[counter]}"; - } -} \ No newline at end of file diff --git a/MetaforceInstaller.Cli/Utils/ArgumentParser.cs b/MetaforceInstaller.Cli/Utils/ArgumentParser.cs deleted file mode 100644 index ffdb561..0000000 --- a/MetaforceInstaller.Cli/Utils/ArgumentParser.cs +++ /dev/null @@ -1,53 +0,0 @@ -using MetaforceInstaller.Core.Models; - -namespace MetaforceInstaller.Cli.Utils; - -public static class ArgumentParser -{ - public static InstallationRequest? ParseArguments(string[] args) - { - var result = new InstallationRequest(); - - for (var i = 0; i < args.Length; i++) - { - switch (args[i].ToLower()) - { - case "--apk": - case "-a": - if (i + 1 < args.Length) - { - result.ApkPath = args[i + 1]; - i++; - } - - break; - - case "--content": - case "-c": - if (i + 1 < args.Length) - { - result.ZipPath = args[i + 1]; - i++; - } - - break; - - case "--output": - case "-o": - if (i + 1 < args.Length) - { - result.OutputPath = args[i + 1]; - i++; - } - - break; - - case "--help": - case "-h": - return null; - } - } - - return result; - } -} \ No newline at end of file diff --git a/MetaforceInstaller.Cloud/ICloudService.cs b/MetaforceInstaller.Cloud/ICloudService.cs new file mode 100644 index 0000000..a179bba --- /dev/null +++ b/MetaforceInstaller.Cloud/ICloudService.cs @@ -0,0 +1,8 @@ +using MetaforceInstaller.Cloud.Models; + +namespace MetaforceInstaller.Cloud; + +public interface ICloudService +{ + Task> GetObjects(string webLink); +} \ No newline at end of file diff --git a/MetaforceInstaller.Cloud/Implementations/MailRu/DTO/CloudObjectResponse.cs b/MetaforceInstaller.Cloud/Implementations/MailRu/DTO/CloudObjectResponse.cs new file mode 100644 index 0000000..7f2bdb3 --- /dev/null +++ b/MetaforceInstaller.Cloud/Implementations/MailRu/DTO/CloudObjectResponse.cs @@ -0,0 +1,181 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace MetaforceInstaller.Cloud.Implementations.MailRu.DTO; + +public sealed class CloudObjectsResponse +{ + [JsonPropertyName("count")] + public CountInfo? Count { get; init; } + + [JsonPropertyName("name")] + public string? Name { get; init; } + + [JsonPropertyName("weblink")] + public string? WebLink { get; init; } + + [JsonPropertyName("size")] + public long? Size { get; init; } + + [JsonPropertyName("rev")] + public long? Rev { get; init; } + + [JsonPropertyName("kind")] + public string? Kind { get; init; } + + [JsonPropertyName("type")] + public string? Type { get; init; } + + [JsonPropertyName("public")] + public PublicInfo? Public { get; init; } + + [JsonPropertyName("list")] + public List? List { get; init; } + + [JsonPropertyName("owner")] + public OwnerInfo? Owner { get; init; } +} + +public sealed class CountInfo +{ + [JsonPropertyName("folders")] + public int? Folders { get; init; } + + [JsonPropertyName("files")] + public int? Files { get; init; } +} + +public sealed class PublicInfo +{ + [JsonPropertyName("type")] + public string? Type { get; init; } + + [JsonPropertyName("name")] + public string? Name { get; init; } + + [JsonPropertyName("id")] + public string? Id { get; init; } + + [JsonPropertyName("ctime")] + public long? CTime { get; init; } + + [JsonPropertyName("views")] + public long? Views { get; init; } + + [JsonPropertyName("downloads")] + public long? Downloads { get; init; } +} + +public sealed class OwnerInfo +{ + [JsonPropertyName("email")] + public string? Email { get; init; } + + [JsonPropertyName("user_flags")] + public UserFlags? UserFlags { get; init; } +} + +public sealed class UserFlags +{ + [JsonPropertyName("PAID_ACCOUNT")] + public bool? PaidAccount { get; init; } +} + +/// +/// Базовый тип элемента из "list". Конкретный тип выбирается по полю "type". +/// +[JsonConverter(typeof(CloudObjectJsonConverter))] +public abstract class CloudObjectBase +{ + [JsonPropertyName("name")] + public string? Name { get; init; } + + [JsonPropertyName("weblink")] + public string? WebLink { get; init; } + + [JsonPropertyName("size")] + public long? Size { get; init; } + + [JsonPropertyName("kind")] + public string? Kind { get; init; } + + [JsonPropertyName("type")] + public string? Type { get; init; } +} + +public sealed class CloudFolderObject : CloudObjectBase +{ + [JsonPropertyName("count")] + public CountInfo? Count { get; init; } + + [JsonPropertyName("rev")] + public long? Rev { get; init; } +} + +public sealed class CloudFileObject : CloudObjectBase +{ + [JsonPropertyName("mtime")] + public long? MTime { get; init; } + + [JsonPropertyName("hash")] + public string? Hash { get; init; } +} + +public sealed class ZipWebLinkRequest +{ + [JsonPropertyName("x-email")] + public string XEmail { get; init; } + + [JsonPropertyName("weblink_list")] + public IReadOnlyList WeblinkList { get; init; } + + [JsonPropertyName("name")] + public string Name { get; init; } +} + +public sealed class ZipWebLinkResponse +{ + [JsonPropertyName("key")] + public string Key { get; init; } +} + +/// +/// Конвертер, который смотрит на поле "type" и десериализует в CloudFolderObject или CloudFileObject. +/// +public sealed class CloudObjectJsonConverter : JsonConverter +{ + public override CloudObjectBase Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + using var doc = JsonDocument.ParseValue(ref reader); + + var root = doc.RootElement; + if (!root.TryGetProperty("type", out var typeProp)) + throw new JsonException("Missing required property 'type' for cloud object."); + + var type = typeProp.GetString(); + + return type switch + { + "folder" => root.Deserialize(options) + ?? throw new JsonException("Failed to deserialize folder object."), + "file" => root.Deserialize(options) + ?? throw new JsonException("Failed to deserialize file object."), + _ => throw new JsonException($"Unknown cloud object type '{type}'.") + }; + } + + public override void Write(Utf8JsonWriter writer, CloudObjectBase value, JsonSerializerOptions options) + { + switch (value) + { + case CloudFolderObject folder: + JsonSerializer.Serialize(writer, folder, options); + break; + case CloudFileObject file: + JsonSerializer.Serialize(writer, file, options); + break; + default: + throw new JsonException($"Unknown runtime type '{value.GetType().Name}'."); + } + } +} \ No newline at end of file diff --git a/MetaforceInstaller.Cloud/Implementations/MailRu/MailRuCloudService.cs b/MetaforceInstaller.Cloud/Implementations/MailRu/MailRuCloudService.cs new file mode 100644 index 0000000..d7ae0ca --- /dev/null +++ b/MetaforceInstaller.Cloud/Implementations/MailRu/MailRuCloudService.cs @@ -0,0 +1,116 @@ +using System.Text; +using System.Text.Json; +using System.Web; +using MetaforceInstaller.Cloud.Implementations.MailRu.DTO; +using MetaforceInstaller.Cloud.Models; + +namespace MetaforceInstaller.Cloud.Implementations.MailRu; + +public class MailRuCloudService : ICloudService +{ + private const string BaseUrl = "https://cloud.mail.ru"; + + private static readonly JsonSerializerOptions JsonOptions = new() + { + PropertyNameCaseInsensitive = true + }; + + private readonly HttpClient _httpClient; + + public MailRuCloudService(HttpClient httpClient) + { + _httpClient = httpClient; + } + + public async Task> GetObjects(string webLink) + { + var dto = await GetFromPublicApi( + path: "/api/v4/public/list", + query: new Dictionary + { + ["weblink"] = webLink, + ["sort"] = "name", + ["order"] = "asc", + ["offset"] = "0", + ["limit"] = "500", + ["version"] = "4" + }).ConfigureAwait(false); + + if (dto?.List is null || dto.List.Count == 0) + return []; + + var result = new List(dto.List.Count); + foreach (var entry in dto.List) + result.Add(Map(entry)); + + return result; + } + + public async Task GetDownloadLink(IEnumerable webLinks, string outputFileName = "archive") + { + var result = await PostToPublicApi( + path: "/api/v3/zip/weblink", + query: new Dictionary(), + new ZipWebLinkRequest + { + XEmail = "anonym", + WeblinkList = webLinks.ToList(), + Name = outputFileName + } + ); + + return result?.Key; + } + + private async Task GetFromPublicApi(string path, IReadOnlyDictionary query) + { + var uri = BuildUri(path, query); + + using var response = await _httpClient.GetAsync(uri).ConfigureAwait(false); + response.EnsureSuccessStatusCode(); + + var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JsonSerializer.Deserialize(json, JsonOptions); + } + + private async Task PostToPublicApi(string path, IReadOnlyDictionary query, + object body) + { + var uri = BuildUri(path, query); + + var jsonBody = JsonSerializer.Serialize(body, JsonOptions); + using var content = new StringContent(jsonBody, Encoding.UTF8, "application/json"); + + using var response = await _httpClient.PostAsync(uri, content).ConfigureAwait(false); + response.EnsureSuccessStatusCode(); + + var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JsonSerializer.Deserialize(json, JsonOptions); + } + + private static Uri BuildUri(string path, IReadOnlyDictionary query) + { + var builder = new UriBuilder(BaseUrl) + { + Port = -1, + Path = path + }; + + var qs = HttpUtility.ParseQueryString(builder.Query); + foreach (var (key, value) in query) + qs[key] = value; + + builder.Query = qs.ToString(); + return builder.Uri; + } + + private static CloudObject Map(CloudObjectBase entry) + { + return new CloudObject + { + Name = entry.Name, + WebLink = entry.WebLink, + Type = entry.Type == "folder" ? CloudObjectType.Folder : CloudObjectType.File + }; + } +} \ No newline at end of file diff --git a/MetaforceInstaller.Cloud/MetaforceInstaller.Cloud.csproj b/MetaforceInstaller.Cloud/MetaforceInstaller.Cloud.csproj new file mode 100644 index 0000000..17b910f --- /dev/null +++ b/MetaforceInstaller.Cloud/MetaforceInstaller.Cloud.csproj @@ -0,0 +1,9 @@ + + + + net9.0 + enable + enable + + + diff --git a/MetaforceInstaller.Cloud/Models/CloudObject.cs b/MetaforceInstaller.Cloud/Models/CloudObject.cs new file mode 100644 index 0000000..643a9d5 --- /dev/null +++ b/MetaforceInstaller.Cloud/Models/CloudObject.cs @@ -0,0 +1,14 @@ +namespace MetaforceInstaller.Cloud.Models; + +public class CloudObject +{ + public string Name { get; set; } + public string WebLink { get; set; } + public CloudObjectType Type { get; set; } +} + +public enum CloudObjectType +{ + Folder, + File +} \ No newline at end of file diff --git a/MetaforceInstaller.Core/Intefaces/IAdbService.cs b/MetaforceInstaller.Core/Intefaces/IAdbService.cs deleted file mode 100644 index 444c237..0000000 --- a/MetaforceInstaller.Core/Intefaces/IAdbService.cs +++ /dev/null @@ -1,18 +0,0 @@ -using MetaforceInstaller.Core.Models; -using MetaforceInstaller.Core.Models; - -namespace MetaforceInstaller.Core.Intefaces; - -public interface IAdbService -{ - event EventHandler? ProgressChanged; - event EventHandler? StatusChanged; - - Task InstallApkAsync(string apkPath, IProgress? progress = null, CancellationToken cancellationToken = default); - Task CopyFileAsync(string localPath, string remotePath, IProgress? progress = null, CancellationToken cancellationToken = default); - DeviceInfo GetDeviceInfo(); - - // Синхронные версии для обратной совместимости - void InstallApk(string apkPath); - void CopyFile(string localPath, string remotePath); -} \ No newline at end of file diff --git a/MetaforceInstaller.Core/MetaforceInstaller.Core.csproj b/MetaforceInstaller.Core/MetaforceInstaller.Core.csproj deleted file mode 100644 index 0a85bfc..0000000 --- a/MetaforceInstaller.Core/MetaforceInstaller.Core.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - net8.0 - enable - enable - - - - - - - - - - - - - - - - - - - - diff --git a/MetaforceInstaller.Core/Models/ApkInfo.cs b/MetaforceInstaller.Core/Models/ApkInfo.cs deleted file mode 100644 index 9f042bf..0000000 --- a/MetaforceInstaller.Core/Models/ApkInfo.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace MetaforceInstaller.Core.Models; - -public record ApkInfo(string PackageName, string VersionName, string VersionCode); \ No newline at end of file diff --git a/MetaforceInstaller.Core/Models/DeviceInfo.cs b/MetaforceInstaller.Core/Models/DeviceInfo.cs deleted file mode 100644 index 802cd3c..0000000 --- a/MetaforceInstaller.Core/Models/DeviceInfo.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace MetaforceInstaller.Core.Models; - -public record DeviceInfo( - string SerialNumber, - string State, - string Model, - string Name -); \ No newline at end of file diff --git a/MetaforceInstaller.Core/Models/InstallationRequest.cs b/MetaforceInstaller.Core/Models/InstallationRequest.cs deleted file mode 100644 index c64b271..0000000 --- a/MetaforceInstaller.Core/Models/InstallationRequest.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace MetaforceInstaller.Core.Models; - -public class InstallationRequest -{ - public string ApkPath { get; set; } - public string ZipPath { get; set; } - public string OutputPath { get; set; } -} \ No newline at end of file diff --git a/MetaforceInstaller.Core/Models/ProgressInfo.cs b/MetaforceInstaller.Core/Models/ProgressInfo.cs deleted file mode 100644 index cc09a74..0000000 --- a/MetaforceInstaller.Core/Models/ProgressInfo.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace MetaforceInstaller.Core.Models; - -public class ProgressInfo -{ - public int PercentageComplete { get; set; } - public long BytesTransferred { get; set; } - public long TotalBytes { get; set; } - public string? Message { get; set; } - public string? CurrentFile { get; set; } - public ProgressType Type { get; set; } -} - -public enum ProgressType -{ - Installation, - FileCopy, - Extraction, - General -} diff --git a/MetaforceInstaller.Core/Services/AdbService.cs b/MetaforceInstaller.Core/Services/AdbService.cs deleted file mode 100644 index ddf790f..0000000 --- a/MetaforceInstaller.Core/Services/AdbService.cs +++ /dev/null @@ -1,206 +0,0 @@ -using System.Reflection; -using AdvancedSharpAdbClient; -using AdvancedSharpAdbClient.DeviceCommands; -using AdvancedSharpAdbClient.Models; -using AdvancedSharpAdbClient.Receivers; -using MetaforceInstaller.Core.Intefaces; -using MetaforceInstaller.Core.Models; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; - -namespace MetaforceInstaller.Core.Services; - -public class AdbService : IAdbService -{ - private readonly ILogger _logger; - private readonly AdbClient _adbClient; - private DeviceData _deviceData; - - public event EventHandler? ProgressChanged; - public event EventHandler? StatusChanged; - - public AdbService(ILogger? logger = null) - { - _logger = logger ?? new NullLogger(); - var adbPath = GetAdbPath(); - var server = new AdbServer(); - var serverStatus = server.StartServer(adbPath, restartServerIfNewer: false); - _adbClient = new AdbClient(); - RefreshDeviceData(); - } - - public void RefreshDeviceData() - { - var devices = _adbClient.GetDevices(); - _deviceData = devices.FirstOrDefault(); - } - - private void ExtractResource(string resourceName, string outputPath) - { - _logger.LogInformation($"Extracting resource: {resourceName} to {outputPath}"); - using var stream = Assembly.GetAssembly(typeof(AdbService)).GetManifestResourceStream(resourceName); - using var fileStream = File.Create(outputPath); - stream.CopyTo(fileStream); - _logger.LogInformation($"Resource extracted: {resourceName} to {outputPath}"); - } - - private string GetAdbPath() - { - var tempDir = Path.Combine(Path.GetTempPath(), "MetaforceInstaller", "adb"); - Directory.CreateDirectory(tempDir); - - var adbPath = Path.Combine(tempDir, "adb.exe"); - - if (File.Exists(adbPath)) return adbPath; - ExtractResource("MetaforceInstaller.Core.adb.adb.exe", adbPath); - ExtractResource("MetaforceInstaller.Core.adb.AdbWinApi.dll", Path.Combine(tempDir, "AdbWinApi.dll")); - ExtractResource("MetaforceInstaller.Core.adb.AdbWinUsbApi.dll", Path.Combine(tempDir, "AdbWinUsbApi.dll")); - - return adbPath; - } - - private void OnProgressChanged(ProgressInfo progressInfo) - { - ProgressChanged?.Invoke(this, progressInfo); - } - - private void OnStatusChanged(string status) - { - StatusChanged?.Invoke(this, status); - } - - public void InstallApk(string apkPath) - { - InstallApkAsync(apkPath).Wait(); - } - - public async Task InstallApkAsync(string apkPath, IProgress? progress = null, - CancellationToken cancellationToken = default) - { - try - { - if (!File.Exists(apkPath)) - { - _logger.LogCritical("Error: Could not find APK file."); - return; - } - - OnStatusChanged("Начинаем установку APK..."); - _logger.LogInformation($"Installing APK: {apkPath}"); - - progress?.Report(new ProgressInfo - { - PercentageComplete = 0, - Message = "Подготовка к установке APK...", - Type = ProgressType.Installation, - CurrentFile = Path.GetFileName(apkPath) - }); - - var packageManager = new PackageManager(_adbClient, _deviceData); - - await Task.Run(() => - { - packageManager.InstallPackage(apkPath, installProgress => - { - var progressInfo = new ProgressInfo - { - PercentageComplete = (int)installProgress.UploadProgress, - Message = $"Установка APK: {installProgress.UploadProgress:F1}%", - Type = ProgressType.Installation, - CurrentFile = Path.GetFileName(apkPath) - }; - - progress?.Report(progressInfo); - OnProgressChanged(progressInfo); - }); - }, cancellationToken); - - OnStatusChanged("APK успешно установлен!"); - _logger.LogInformation("APK successfully installed!"); - } - catch (Exception ex) - { - _logger.LogCritical($"Error: {ex.Message}"); - throw; - } - } - - public void CopyFile(string localPath, string remotePath) - { - CopyFileAsync(localPath, remotePath).Wait(); - } - - public async Task CopyFileAsync(string localPath, string remotePath, IProgress? progress = null, - CancellationToken cancellationToken = default) - { - try - { - if (!File.Exists(localPath)) - { - _logger.LogCritical($"Error: Could not find file: {localPath}"); - return; - } - - OnStatusChanged("Начинаем копирование файла..."); - _logger.LogInformation($"Copying file: {localPath} to {remotePath}"); - - var fileInfo = new FileInfo(localPath); - - progress?.Report(new ProgressInfo - { - PercentageComplete = 0, - Message = "Подготовка к копированию файла...", - Type = ProgressType.FileCopy, - CurrentFile = Path.GetFileName(localPath), - TotalBytes = fileInfo.Length - }); - - var remoteDir = Path.GetDirectoryName(remotePath)?.Replace('\\', '/'); - if (!string.IsNullOrEmpty(remoteDir)) - { - var reciever = new ConsoleOutputReceiver(); - await Task.Run( - () => { _adbClient.ExecuteRemoteCommand($"mkdir -p \"{remoteDir}\"", _deviceData, reciever); }, - cancellationToken); - } - - _logger.LogInformation($"Ensured remote directory: {remoteDir}"); - - await Task.Run(() => - { - using var fileStream = File.OpenRead(localPath); - var syncService = new SyncService(_adbClient, _deviceData); - - syncService.Push(fileStream, remotePath, UnixFileStatus.DefaultFileMode, DateTime.Now, - copyProgress => - { - var progressInfo = new ProgressInfo - { - PercentageComplete = (int)copyProgress.ProgressPercentage, - BytesTransferred = copyProgress.ReceivedBytesSize, - TotalBytes = copyProgress.TotalBytesToReceive, - Message = $"Копирование: {copyProgress.ProgressPercentage:F1}%", - Type = ProgressType.FileCopy, - CurrentFile = Path.GetFileName(localPath) - }; - - progress?.Report(progressInfo); - OnProgressChanged(progressInfo); - }); - }, cancellationToken); - - OnStatusChanged("Файл успешно скопирован!"); - _logger.LogInformation("File successfully copied!"); - } - catch (Exception ex) - { - _logger.LogCritical($"Error: {ex.Message}"); - throw; - } - } - - public DeviceInfo GetDeviceInfo() - { - return new DeviceInfo(_deviceData.Serial, _deviceData.State.ToString(), _deviceData.Model, _deviceData.Name); - } -} \ No newline at end of file diff --git a/MetaforceInstaller.Core/Services/ApkScrapper.cs b/MetaforceInstaller.Core/Services/ApkScrapper.cs deleted file mode 100644 index c06c543..0000000 --- a/MetaforceInstaller.Core/Services/ApkScrapper.cs +++ /dev/null @@ -1,19 +0,0 @@ -using AlphaOmega.Debug; -using MetaforceInstaller.Core.Models; - -namespace MetaforceInstaller.Core.Services; - -public static class ApkScrapper -{ - public static ApkInfo GetApkInfo(string apkPath) - { - using var apk = new ApkFile(apkPath); - if (apk is { IsValid: true, AndroidManifest: not null }) - { - return new ApkInfo(apk.AndroidManifest.Package, apk.AndroidManifest.VersionName, - apk.AndroidManifest.VersionCode); - } - - throw new Exception("Invalid APK file"); - } -} \ No newline at end of file diff --git a/MetaforceInstaller.Core/adb/AdbWinApi.dll b/MetaforceInstaller.Core/adb/AdbWinApi.dll deleted file mode 100644 index 7abe26c..0000000 Binary files a/MetaforceInstaller.Core/adb/AdbWinApi.dll and /dev/null differ diff --git a/MetaforceInstaller.Core/adb/AdbWinUsbApi.dll b/MetaforceInstaller.Core/adb/AdbWinUsbApi.dll deleted file mode 100644 index e7a6de1..0000000 Binary files a/MetaforceInstaller.Core/adb/AdbWinUsbApi.dll and /dev/null differ diff --git a/MetaforceInstaller.Core/adb/adb.exe b/MetaforceInstaller.Core/adb/adb.exe deleted file mode 100644 index 85bfeaa..0000000 Binary files a/MetaforceInstaller.Core/adb/adb.exe and /dev/null differ diff --git a/MetaforceInstaller.UI/App.axaml b/MetaforceInstaller.UI/App.axaml deleted file mode 100644 index d947dd9..0000000 --- a/MetaforceInstaller.UI/App.axaml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/MetaforceInstaller.UI/App.axaml.cs b/MetaforceInstaller.UI/App.axaml.cs deleted file mode 100644 index 16212ac..0000000 --- a/MetaforceInstaller.UI/App.axaml.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Avalonia; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Markup.Xaml; - -namespace MetaforceInstaller.UI; - -public partial class App : Application -{ - public override void Initialize() - { - AvaloniaXamlLoader.Load(this); - } - - public override void OnFrameworkInitializationCompleted() - { - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) - { - desktop.MainWindow = new MainWindow(); - } - - base.OnFrameworkInitializationCompleted(); - } -} \ No newline at end of file diff --git a/MetaforceInstaller.UI/Images/logo_black.svg b/MetaforceInstaller.UI/Images/logo_black.svg deleted file mode 100644 index d41fcc9..0000000 --- a/MetaforceInstaller.UI/Images/logo_black.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/MetaforceInstaller.UI/Images/logo_red.svg b/MetaforceInstaller.UI/Images/logo_red.svg deleted file mode 100644 index 1b73fdc..0000000 --- a/MetaforceInstaller.UI/Images/logo_red.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/MetaforceInstaller.UI/Images/logo_white.svg b/MetaforceInstaller.UI/Images/logo_white.svg deleted file mode 100644 index 12ba8d1..0000000 --- a/MetaforceInstaller.UI/Images/logo_white.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/MetaforceInstaller.UI/MainWindow.axaml b/MetaforceInstaller.UI/MainWindow.axaml deleted file mode 100644 index 61a426d..0000000 --- a/MetaforceInstaller.UI/MainWindow.axaml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -