using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using UnityEditor; using UnityEditor.Localization; using UnityEngine; namespace Crowdin.Plugin.Operations { using Helpers; using Helpers.PluginLocalization; using Helpers.UnityLocalization; using Models; using Models.PushData; using Models.Translations; using Server_API; using Server_API.Helpers; using Server_API.Serializable; /// Pushes source assets (images, audio, ...) to Crowdin, one subdirectory per table under the /// plugin's root directory. public static class PushAssets { private const int MaxConcurrentUploads = 5; public static async Task RunAsync( PushAssetsOptions options, IProgress progress, CancellationToken cancellationToken) { int rootDirId = await DirectoriesHelper.EnsureRootDirectoryAsync(cancellationToken); progress.Report(new OperationProgress( LocalizationHelper.GetLocalStringByKey(LocalKeys.start_export_assets))); TranslationsHelper.RefreshAllAssetsTranslations(); foreach (string tableName in options.Tables) { var collection = LocalizationEditorSettings.GetAssetTableCollection(tableName); foreach (var row in collection.GetRowEnumerator()) { ExportDataHelper.ParseAssetRowToCrowdinTranslation(row, tableName); } } Dictionary tableDirIds = await DirectoriesHelper.EnsureDirectoriesAsync( options.Tables.Select(tableName => (name: tableName, title: tableName)).ToList(), rootDirId, cancellationToken); var pushList = new List(); foreach (string tableName in options.Tables) { FillPushAssetsData(tableDirIds[tableName], tableName, pushList); } var perTable = new Dictionary(); int sentAssets = 0; for (var offset = 0; offset < pushList.Count; offset += MaxConcurrentUploads) { IEnumerable batch = pushList.Skip(offset).Take(MaxConcurrentUploads); (PushAssetData Item, FileData Result)[] results = await Task.WhenAll( batch.Select(async item => (item, await UploadAssetAsync(item, progress, cancellationToken)))); foreach ((PushAssetData item, FileData data) in results) { if (data is null) { continue; } sentAssets++; string tableName = item.translationAsset.exportedFromTable; perTable[tableName] = perTable.GetValueOrDefault(tableName) + 1; progress.Report(new OperationProgress(LocalizationHelper.GetLocalStringByKey( LocalKeys.added_translation_asset, data.name, data.title))); } } return new PushAssetsResult(sentAssets, perTable); } private static async Task UploadAssetAsync( PushAssetData data, IProgress progress, CancellationToken cancellationToken) { TranslationAsset translationAsset = data.translationAsset; var filename = $"{translationAsset.key}{Path.GetExtension(translationAsset.filePath)}"; try { return await StorageHelper.UploadSourceFileAsync( translationAsset.key, filename, translationAsset.filePath, data.directoryId, includeTranslationsInFile: false, cancellationToken); } catch (CrowdinApiException ex) { Debug.LogException(ex); progress.Report(new OperationProgress(LocalizationHelper.GetLocalStringByException(ex))); return null; } } private static void FillPushAssetsData(int directoryId, string tableName, List pushList) { IEnumerable crowdinTranslationAssets = TranslationsHelper.GetTranslationAssets(tableName); foreach (TranslationAsset translationAsset in crowdinTranslationAssets) { if (translationAsset.sourceObject is null) { var sourceTranslation = translationAsset.translations.Find(item => item.language == SettingsHelper.GetSourceLanguage()); if (sourceTranslation != null) { translationAsset.sourceObject = sourceTranslation.asset; } else { continue; } } translationAsset.filePath = AssetDatabase.GetAssetPath(translationAsset.sourceObject); if (translationAsset.filePath.Length > 0) { pushList.Add(new PushAssetData(directoryId, translationAsset)); } } } } }