From 6bdd4f5df97c5b1536f1ca07976f78d622b38832 Mon Sep 17 00:00:00 2001 From: Andreas Stange Date: Thu, 24 Mar 2022 21:23:03 +0100 Subject: [PATCH 1/5] SongSelect: right click to open song menu, drag only listening for left click --- .../Common/UIToolkit/Drag/AbstractDragControl.cs | 14 ++++++++++++++ .../SongSelect/SongRoulette/SongEntryControl.cs | 14 ++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/UltraStar Play/Assets/Common/UIToolkit/Drag/AbstractDragControl.cs b/UltraStar Play/Assets/Common/UIToolkit/Drag/AbstractDragControl.cs index 7437a0ab5..41a0745ad 100644 --- a/UltraStar Play/Assets/Common/UIToolkit/Drag/AbstractDragControl.cs +++ b/UltraStar Play/Assets/Common/UIToolkit/Drag/AbstractDragControl.cs @@ -36,6 +36,8 @@ public abstract class AbstractDragControl : INeedInjection, IInjectionFin private readonly List disposables = new List(); + public IReadOnlyCollection ButtonFilter { get; set; } = new List { 0, 1, 2 }; + public virtual void OnInjectionFinished() { this.panelHelper = new PanelHelper(uiDocument); @@ -70,6 +72,12 @@ public void RemoveListener(IDragListener listener) protected virtual void OnPointerDown(IPointerEvent evt) { + if (!ButtonFilter.IsNullOrEmpty() + && !ButtonFilter.Contains(evt.button)) + { + return; + } + dragControlPointerDownEvent = new DragControlPointerEvent(evt); DragState.Value = EDragState.WaitingForDistanceThreshold; } @@ -92,6 +100,12 @@ protected virtual void OnPointerMove(IPointerEvent evt) protected virtual void OnPointerUp(IPointerEvent evt) { + if (!ButtonFilter.IsNullOrEmpty() + && !ButtonFilter.Contains(evt.button)) + { + return; + } + if (DragState.Value == EDragState.Dragging) { OnEndDrag(new DragControlPointerEvent(evt)); diff --git a/UltraStar Play/Assets/Scenes/SongSelect/SongRoulette/SongEntryControl.cs b/UltraStar Play/Assets/Scenes/SongSelect/SongRoulette/SongEntryControl.cs index 695244954..0a317a6fd 100644 --- a/UltraStar Play/Assets/Scenes/SongSelect/SongRoulette/SongEntryControl.cs +++ b/UltraStar Play/Assets/Scenes/SongSelect/SongRoulette/SongEntryControl.cs @@ -319,6 +319,8 @@ public void OnInjectionFinished() .WithRootVisualElement(songEntryUiRoot) .CreateAndInject(); dragControl.AddListener(this); + // Only listen to left mouse button / touch gesture + dragControl.ButtonFilter = new List { 0 }; // Ignore button click after dragging dragControl.DragState.Subscribe(dragState => @@ -329,7 +331,7 @@ public void OnInjectionFinished() } }); - songEntryUiRoot.RegisterCallback(_ => OnPointerDown(), TrickleDown.TrickleDown); + songEntryUiRoot.RegisterCallback(evt => OnPointerDown(evt), TrickleDown.TrickleDown); songEntryUiRoot.RegisterCallback(_ => OnPointerUp(), TrickleDown.TrickleDown); // Stop coroutine when dragging @@ -344,8 +346,16 @@ public void OnInjectionFinished() UpdateTranslation(); } - private void OnPointerDown() + private void OnPointerDown(IPointerEvent pointerEvent) { + if (pointerEvent.button == 1) + { + // Right click to open song menu + songRouletteControl.SelectSong(songMeta); + songRouletteControl.ShowSongMenuOverlay(); + return; + } + isPointerDown = true; StartShowSongMenuOverlayCoroutine(); } From 92dafe7276bf695cfbc9f6599f604f6f8bd97ba1 Mon Sep 17 00:00:00 2001 From: Andreas Stange Date: Thu, 24 Mar 2022 21:23:38 +0100 Subject: [PATCH 2/5] replace backslash in path TextField with forward slash (backslash escapes stuff in TextField) --- .../UI/Dialogs/PathInputDialogControl.cs | 8 +++++++ .../UI/Dialogs/TextInputDialogControl.cs | 4 ++-- .../BackslashReplacingTextFieldControl.cs | 17 ++++++++------- .../Common/UIToolkit/PathTextFieldControl.cs | 21 +++++++++++++++++++ .../UIToolkit/PathTextFieldControl.cs.meta | 3 +++ .../SongLibraryOptionsSceneControl.cs | 4 ++-- .../LyricsArea/LyricsAreaControl.cs | 6 ++++-- 7 files changed, 50 insertions(+), 13 deletions(-) create mode 100644 UltraStar Play/Assets/Common/UIToolkit/PathTextFieldControl.cs create mode 100644 UltraStar Play/Assets/Common/UIToolkit/PathTextFieldControl.cs.meta diff --git a/UltraStar Play/Assets/Common/UI/Dialogs/PathInputDialogControl.cs b/UltraStar Play/Assets/Common/UI/Dialogs/PathInputDialogControl.cs index a8afe1e46..eb1679040 100644 --- a/UltraStar Play/Assets/Common/UI/Dialogs/PathInputDialogControl.cs +++ b/UltraStar Play/Assets/Common/UI/Dialogs/PathInputDialogControl.cs @@ -1,10 +1,18 @@ using System; using System.IO; +using UniRx; public class PathInputDialogControl : TextInputDialogControl { public override void OnInjectionFinished() { + if (backslashReplacingTextFieldControl == null) + { + backslashReplacingTextFieldControl = new PathTextFieldControl(textField); + backslashReplacingTextFieldControl.ValueChangedEventStream + .Subscribe(newValue => ValidateValue(newValue, true)); + } + base.OnInjectionFinished(); ValidateValueCallback = newValue => diff --git a/UltraStar Play/Assets/Common/UI/Dialogs/TextInputDialogControl.cs b/UltraStar Play/Assets/Common/UI/Dialogs/TextInputDialogControl.cs index 7c0dc28ec..5c6d838f3 100644 --- a/UltraStar Play/Assets/Common/UI/Dialogs/TextInputDialogControl.cs +++ b/UltraStar Play/Assets/Common/UI/Dialogs/TextInputDialogControl.cs @@ -26,7 +26,7 @@ public class TextInputDialogControl : AbstractDialogControl, IInjectionFinishedL [Inject(UxmlName = R.UxmlNames.cancelButton)] protected Button cancelButton; - private BackslashReplacingTextFieldControl backslashReplacingTextFieldControl; + protected BackslashReplacingTextFieldControl backslashReplacingTextFieldControl; private readonly Subject submitValueEventStream = new Subject(); public IObservable SubmitValueEventStream => submitValueEventStream; @@ -123,7 +123,7 @@ private void TrySubmitValue(string textValue) } } - private void ValidateValue(string textValue, bool showMessageIfInvalid) + protected void ValidateValue(string textValue, bool showMessageIfInvalid) { if (ValidateValueCallback == null) { diff --git a/UltraStar Play/Assets/Common/UIToolkit/BackslashReplacingTextFieldControl.cs b/UltraStar Play/Assets/Common/UIToolkit/BackslashReplacingTextFieldControl.cs index 356807acd..bb5b05285 100644 --- a/UltraStar Play/Assets/Common/UIToolkit/BackslashReplacingTextFieldControl.cs +++ b/UltraStar Play/Assets/Common/UIToolkit/BackslashReplacingTextFieldControl.cs @@ -16,15 +16,18 @@ */ public class BackslashReplacingTextFieldControl { - private const string BackslashReplacement = "\"; + private const string DefaultBackslashReplacement = "\"; private TextField textField; private readonly Subject valueChangedEventStream = new Subject(); public IObservable ValueChangedEventStream => valueChangedEventStream; - public BackslashReplacingTextFieldControl(TextField textField) + private readonly string backslashReplacement; + + public BackslashReplacingTextFieldControl(TextField textField, string backslashReplacement = DefaultBackslashReplacement) { + this.backslashReplacement = backslashReplacement; textField.RegisterValueChangedCallback(evt => { string newValueEscaped = EscapeBackslashes(evt.newValue); @@ -34,16 +37,16 @@ public BackslashReplacingTextFieldControl(TextField textField) valueChangedEventStream.OnNext(newValueUnescaped); }); - textField.value = textField.value.Replace("\\", BackslashReplacement); + textField.value = textField.value.Replace("\\", backslashReplacement); } - public static string EscapeBackslashes(string text) + public string EscapeBackslashes(string text) { - return text.Replace("\\", BackslashReplacement); + return text.Replace("\\", backslashReplacement); } - public static string UnescapeBackslashes(string text) + public string UnescapeBackslashes(string text) { - return text.Replace(BackslashReplacement, "\\"); + return text.Replace(backslashReplacement, "\\"); } } diff --git a/UltraStar Play/Assets/Common/UIToolkit/PathTextFieldControl.cs b/UltraStar Play/Assets/Common/UIToolkit/PathTextFieldControl.cs new file mode 100644 index 000000000..9e701592b --- /dev/null +++ b/UltraStar Play/Assets/Common/UIToolkit/PathTextFieldControl.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UIElements; +using UniInject; +using UniRx; + +// Disable warning about fields that are never assigned, their values are injected. +#pragma warning disable CS0649 + +public class PathTextFieldControl : BackslashReplacingTextFieldControl +{ + private const string BackslashReplacement = "/"; + + public PathTextFieldControl(TextField textField) + : base(textField, BackslashReplacement) + { + } +} diff --git a/UltraStar Play/Assets/Common/UIToolkit/PathTextFieldControl.cs.meta b/UltraStar Play/Assets/Common/UIToolkit/PathTextFieldControl.cs.meta new file mode 100644 index 000000000..c62b3adcd --- /dev/null +++ b/UltraStar Play/Assets/Common/UIToolkit/PathTextFieldControl.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1dcd2eaeca5b498e965102a48c00deb7 +timeCreated: 1648152473 \ No newline at end of file diff --git a/UltraStar Play/Assets/Scenes/Options/SongLibraryOptions/SongLibraryOptionsSceneControl.cs b/UltraStar Play/Assets/Scenes/Options/SongLibraryOptions/SongLibraryOptionsSceneControl.cs index b49ca352e..aa874f7dc 100644 --- a/UltraStar Play/Assets/Scenes/Options/SongLibraryOptions/SongLibraryOptionsSceneControl.cs +++ b/UltraStar Play/Assets/Scenes/Options/SongLibraryOptions/SongLibraryOptionsSceneControl.cs @@ -125,8 +125,8 @@ void CheckFolderExists(string path) TextField textField = result.Q(R.UxmlNames.pathTextField); textField.value = songDir; - BackslashReplacingTextFieldControl backslashReplacingTextFieldControl = new BackslashReplacingTextFieldControl(textField); - backslashReplacingTextFieldControl.ValueChangedEventStream + PathTextFieldControl pathTextFieldControl = new PathTextFieldControl(textField); + pathTextFieldControl.ValueChangedEventStream .Subscribe(newValueUnescaped => { settings.GameSettings.songDirs[indexInList] = newValueUnescaped; diff --git a/UltraStar Play/Assets/Scenes/SongEditor/LyricsArea/LyricsAreaControl.cs b/UltraStar Play/Assets/Scenes/SongEditor/LyricsArea/LyricsAreaControl.cs index 9f80083a4..57579e524 100644 --- a/UltraStar Play/Assets/Scenes/SongEditor/LyricsArea/LyricsAreaControl.cs +++ b/UltraStar Play/Assets/Scenes/SongEditor/LyricsArea/LyricsAreaControl.cs @@ -62,6 +62,8 @@ public Voice Voice public void OnInjectionFinished() { + BackslashReplacingTextFieldControl backslashReplacingTextFieldControl = null; + voice = songMeta.GetVoices()[0]; UpdateLyrics(); textField.RegisterCallback(evt => @@ -72,7 +74,7 @@ public void OnInjectionFinished() { if (lyricsAreaMode == LyricsAreaMode.EditMode) { - OnEndEdit(BackslashReplacingTextFieldControl.UnescapeBackslashes(textField.text)); + OnEndEdit(backslashReplacingTextFieldControl.UnescapeBackslashes(textField.text)); } }); @@ -81,7 +83,7 @@ public void OnInjectionFinished() textField.doubleClickSelectsWord = true; textField.tripleClickSelectsLine = true; - BackslashReplacingTextFieldControl backslashReplacingTextFieldControl = new BackslashReplacingTextFieldControl(textField); + backslashReplacingTextFieldControl = new BackslashReplacingTextFieldControl(textField); // Replace white space with visible characters when in edit mode backslashReplacingTextFieldControl.ValueChangedEventStream .Subscribe(newValue => From 495b9c1af35894e7fca325971df29d8fa89f9483 Mon Sep 17 00:00:00 2001 From: Andreas Stange Date: Thu, 24 Mar 2022 21:37:21 +0100 Subject: [PATCH 3/5] do not throw exception when when optional field occurs multiple times in a song, instead log a warning --- .../Assets/Common/Model/Song/Builder/SongMetaBuilder.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/UltraStar Play/Assets/Common/Model/Song/Builder/SongMetaBuilder.cs b/UltraStar Play/Assets/Common/Model/Song/Builder/SongMetaBuilder.cs index d8aa8a215..8a891b49d 100644 --- a/UltraStar Play/Assets/Common/Model/Song/Builder/SongMetaBuilder.cs +++ b/UltraStar Play/Assets/Common/Model/Song/Builder/SongMetaBuilder.cs @@ -99,9 +99,12 @@ public static SongMeta ParseFile(string path, Encoding enc = null) { if (otherFields.ContainsKey(tag)) { - throw new SongMetaBuilderException("Cannot set '" + tag + "' twice in file " + path); + Debug.LogWarning($"Cannot set '{tag}' twice in file {path}"); + } + else + { + otherFields[tag] = val; } - otherFields.Add(tag, val); } } From 12003cd45966653a2aa9e9fb36720431a978e2ea Mon Sep 17 00:00:00 2001 From: Andreas Stange Date: Thu, 24 Mar 2022 21:37:37 +0100 Subject: [PATCH 4/5] catch exception and show error message if loading a song failed --- .../Scenes/SongSelect/Preview/SongPreviewControl.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/UltraStar Play/Assets/Scenes/SongSelect/Preview/SongPreviewControl.cs b/UltraStar Play/Assets/Scenes/SongSelect/Preview/SongPreviewControl.cs index b9f0050ae..aa625b76d 100644 --- a/UltraStar Play/Assets/Scenes/SongSelect/Preview/SongPreviewControl.cs +++ b/UltraStar Play/Assets/Scenes/SongSelect/Preview/SongPreviewControl.cs @@ -201,7 +201,18 @@ private void StartVideoPreview(SongMeta songMeta) private void StartAudioPreview(SongMeta songMeta, int previewStartInMillis) { - songAudioPlayer.Init(songMeta); + try + { + songAudioPlayer.Init(songMeta); + } + catch (Exception ex) + { + Debug.LogException(ex); + string errorMessage = $"Audio could not be loaded (artist: {songMeta.Artist}, title: {songMeta.Title})"; + uiManager.CreateNotificationVisualElement(errorMessage); + return; + } + songAudioPlayer.PositionInSongInMillis = previewStartInMillis; songAudioPlayer.audioPlayer.volume = 0; if (songAudioPlayer.HasAudioClip) From 2b86c6dffdea65ee3b9b56e2acf5ebc23430bc19 Mon Sep 17 00:00:00 2001 From: Andreas Stange Date: Thu, 24 Mar 2022 22:56:42 +0100 Subject: [PATCH 5/5] ContentDownloadScene: support downloading and extracting ZIP archive - use song-stream repo as default (user does not need to download > 200MB to try out the game) --- .../Translations/messages.properties | 2 +- .../Translations/messages_de.properties | 2 +- .../ContentDownloadSceneControl.cs | 172 +++++++++++++----- .../ContentDownloadSceneUi.uxml | 4 +- 4 files changed, 133 insertions(+), 47 deletions(-) diff --git a/UltraStar Play/Assets/Resources/Translations/messages.properties b/UltraStar Play/Assets/Resources/Translations/messages.properties index 859bb741b..f704b4487 100644 --- a/UltraStar Play/Assets/Resources/Translations/messages.properties +++ b/UltraStar Play/Assets/Resources/Translations/messages.properties @@ -240,7 +240,7 @@ options_sampleRate_auto=Auto # Content Download contentDownloadScene_title=Content Download -contentDownloadScene_archiveUrlLabel=Archive URL (tar file) +contentDownloadScene_archiveUrlLabel=Archive URL contentDownloadScene_startDownloadButton=Start Download contentDownloadScene_cancelDownloadButton=Cancel Download contentDownloadScene_status_finished=Finished diff --git a/UltraStar Play/Assets/Resources/Translations/messages_de.properties b/UltraStar Play/Assets/Resources/Translations/messages_de.properties index e2893b966..02c159a80 100644 --- a/UltraStar Play/Assets/Resources/Translations/messages_de.properties +++ b/UltraStar Play/Assets/Resources/Translations/messages_de.properties @@ -240,7 +240,7 @@ options_sampleRate_auto=Auto # Content Download contentDownloadScene_title=Downloads -contentDownloadScene_archiveUrlLabel=Archiv-URL (.tar-Datei) +contentDownloadScene_archiveUrlLabel=Archiv-URL contentDownloadScene_startDownloadButton=Download Starten contentDownloadScene_cancelDownloadButton=Download Abbrechen contentDownloadScene_status_finished=Fertig diff --git a/UltraStar Play/Assets/Scenes/Options/ContentDownload/ContentDownloadSceneControl.cs b/UltraStar Play/Assets/Scenes/Options/ContentDownload/ContentDownloadSceneControl.cs index ac5eac0ff..90ba81be4 100644 --- a/UltraStar Play/Assets/Scenes/Options/ContentDownload/ContentDownloadSceneControl.cs +++ b/UltraStar Play/Assets/Scenes/Options/ContentDownload/ContentDownloadSceneControl.cs @@ -8,8 +8,10 @@ using System.IO; using UnityEngine.Networking; using ICSharpCode.SharpZipLib.Tar; +using ICSharpCode.SharpZipLib.Zip; using static ThreadPool; using System.Text; +using ICSharpCode.SharpZipLib.Core; using PrimeInputActions; using ProTrans; using UnityEngine.UIElements; @@ -21,7 +23,8 @@ public class ContentDownloadSceneControl : MonoBehaviour, INeedInjection, ITrans { private static readonly List defaultArchiveUrls = new List { - "https://42.usplay.net/ultrastar-songs-cc.tar" + "https://github.com/UltraStar-Deluxe/songs-stream/archive/refs/heads/main.zip", + "https://42.usplay.net/ultrastar-songs-cc.tar", }; [Inject] @@ -73,6 +76,10 @@ public class ContentDownloadSceneControl : MonoBehaviour, INeedInjection, ITrans private UnityWebRequest downloadRequest; + // The Ui log may only be filled from the main thread. + // This string caches new log lines for other threads. + private string newLogText; + void Start() { statusLabel.text = ""; @@ -120,11 +127,32 @@ void Update() downloadRequest = null; SetCanceledStatus(); } + + if (!newLogText.IsNullOrEmpty()) + { + logText.value = newLogText + logText.value; + newLogText = ""; + } + } + + private string GetDownloadTargetPath(string url) + { + Uri uri = new Uri(url); + string filename = Path.GetFileName(uri.LocalPath); + string targetPath = ApplicationManager.PersistentTempPath() + "/" + filename; + return targetPath; + } + + private DownloadHandler CreateDownloadHandler(string targetPath) + { + DownloadHandlerFile downloadHandler = new DownloadHandlerFile(targetPath); + downloadHandler.removeFileOnAbort = true; + return downloadHandler; } private void StartDownload() { - StartCoroutine(DownloadFileAsync(DownloadUrl, ApplicationManager.PersistentTempPath())); + StartCoroutine(DownloadFileAsync(DownloadUrl)); } private void CancelDownload() @@ -142,7 +170,7 @@ private void FetchFileSize() StartCoroutine(FileSizeUpdateAsync(DownloadUrl)); } - private IEnumerator DownloadFileAsync(string url, string targetFolder) + private IEnumerator DownloadFileAsync(string url) { if (downloadRequest != null && !downloadRequest.isDone) @@ -159,13 +187,10 @@ private IEnumerator DownloadFileAsync(string url, string targetFolder) Debug.Log($"Started download: {url}"); AddToUiLog($"Started download"); - Uri uri = new Uri(url); - string filename = Path.GetFileName(uri.LocalPath); - string targetPath = Path.Combine(targetFolder, filename); + string targetPath = GetDownloadTargetPath(url); + DownloadHandler downloadHandler = CreateDownloadHandler(targetPath); downloadRequest = UnityWebRequest.Get(url); - DownloadHandlerFile downloadHandler = new DownloadHandlerFile(targetPath); - downloadHandler.removeFileOnAbort = true; downloadRequest.downloadHandler = downloadHandler; StartCoroutine(TrackProgressAsync()); @@ -181,7 +206,7 @@ private IEnumerator DownloadFileAsync(string url, string targetFolder) { statusLabel.text = "100%"; AddToUiLog($"Download saved to {targetPath}. {downloadRequest.error}"); - UnpackTar(targetPath); + UnpackArchive(targetPath); } } @@ -224,7 +249,7 @@ private void AddToDebugAndUiLog(string message, bool isError = false) private void AddToUiLog(string message) { - logText.value = message + "\n" + logText.value; + newLogText += message + "\n"; } public void UpdateFileSize() @@ -241,34 +266,46 @@ private IEnumerator FileSizeUpdateAsync(string url) yield break; } - Debug.Log($"Fetching size of {url}"); - using (UnityWebRequest request = UnityWebRequest.Head(url)) - { - yield return request.SendWebRequest(); + using UnityWebRequest request = UnityWebRequest.Head(url); + yield return request.SendWebRequest(); - if (request.isNetworkError || request.isHttpError) + if (request.isNetworkError || request.isHttpError) + { + Debug.LogError($"Error fetching size: {request.error}"); + AddToUiLog($"Error fetching size: {request.error}"); + ResetFileSizeText(); + } + else + { + string contentLength = request.GetResponseHeader("Content-Length"); + if (contentLength.IsNullOrEmpty()) { - - Debug.LogError($"Error fetching size: {request.error}"); - AddToUiLog($"Error fetching size: {request.error}"); ResetFileSizeText(); } else { - long size = Convert.ToInt64(request.GetResponseHeader("Content-Length")); - fileSize.text = (size / 1024 / 1024) + " MB"; + long size = Convert.ToInt64(contentLength); + long kiloByte = size / 1024; + if (kiloByte > 1024) + { + fileSize.text = Math.Round((double)kiloByte / 1024) + " MB"; + } + else + { + fileSize.text = Math.Round((double)kiloByte) + " KB"; + } } } } - private void UnpackTar(string tarPath) + private void UnpackArchive(string archivePath) { if (downloadRequest == null) { return; } - if (!File.Exists(tarPath)) + if (!File.Exists(archivePath)) { AddToDebugAndUiLog("Can not unpack file because it does not exist on the storage! Did the download fail?", true); return; @@ -278,27 +315,76 @@ private void UnpackTar(string tarPath) string songsPath = ApplicationManager.PersistentSongsPath(); PoolHandle handle = ThreadPool.QueueUserWorkItem(poolHandle => { - using (Stream tarStream = File.OpenRead(tarPath)) + if (archivePath.ToLowerInvariant().EndsWith("tar")) { - using (TarArchive archive = TarArchive.CreateInputTarArchive(tarStream, Encoding.UTF8)) - { - try - { - archive.ExtractContents(songsPath); - poolHandle.done = true; - } - catch (Exception ex) - { - AddToDebugAndUiLog($"Unpacking failed: {ex.Message}"); - SetErrorStatus(); - } - } + ExtractTarArchive(archivePath, songsPath, poolHandle); + } + else if (archivePath.ToLowerInvariant().EndsWith("zip")) + { + ExtractZipArchive(archivePath, songsPath, poolHandle); } }); - StartCoroutine(TrackUnpackAsync(handle, tarPath, songsPath)); + StartCoroutine(TrackUnpackAsync(handle, archivePath, songsPath)); + } + + private void ExtractZipArchive(string archivePath, string targetFolder, PoolHandle poolHandle) + { + using Stream archiveStream = File.OpenRead(archivePath); + using ZipFile zipFile = new ZipFile(archiveStream); + + try + { + foreach (ZipEntry entry in zipFile) + { + ExtractZipEntry(zipFile, entry, targetFolder); + } + + poolHandle.done = true; + } + catch (Exception ex) + { + AddToDebugAndUiLog($"Unpacking failed: {ex.Message}"); + SetErrorStatus(); + } + } + + private void ExtractZipEntry(ZipFile zipFile, ZipEntry zipEntry, string targetFolder) + { + string entryPath = zipEntry.Name; + if (!zipEntry.IsFile) + { + string targetSubFolder = targetFolder + "/" + zipEntry.Name; + Directory.CreateDirectory(targetSubFolder); + return; + } + + Debug.Log($"Extracting {entryPath}"); + string targetFilePath = targetFolder + "/" + entryPath; + + byte[] buffer = new byte[4096]; + using Stream zipEntryStream = zipFile.GetInputStream(zipEntry); + using FileStream targetFileStream = File.Create(targetFilePath); + StreamUtils.Copy(zipEntryStream, targetFileStream, buffer); + } + + private void ExtractTarArchive(string archivePath, string targetFolder, PoolHandle poolHandle) + { + using Stream archiveStream = File.OpenRead(archivePath); + using TarArchive archive = TarArchive.CreateInputTarArchive(archiveStream, Encoding.UTF8); + + try + { + archive.ExtractContents(targetFolder); + poolHandle.done = true; + } + catch (Exception ex) + { + AddToDebugAndUiLog($"Unpacking failed: {ex.Message}"); + SetErrorStatus(); + } } - private IEnumerator TrackUnpackAsync(PoolHandle handle, string tarPath, string songsPath) + private IEnumerator TrackUnpackAsync(PoolHandle handle, string archivePath, string songsPath) { if (downloadRequest == null) { @@ -329,7 +415,7 @@ private IEnumerator TrackUnpackAsync(PoolHandle handle, string tarPath, string s if (handle == null) { - AddToDebugAndUiLog($"Unpacking the song package failed. Handle was null for {tarPath}.", true); + AddToDebugAndUiLog($"Unpacking the song package failed. Handle was null for {archivePath}.", true); statusLabel.text = "Failed. Handle was null"; } @@ -354,12 +440,12 @@ private IEnumerator TrackUnpackAsync(PoolHandle handle, string tarPath, string s } else { - AddToDebugAndUiLog($"Unpacking the song package failed with an unknown error. Please check the log. File: {tarPath}", true); + AddToDebugAndUiLog($"Unpacking the song package failed with an unknown error. Please check the log. File: {archivePath}", true); statusLabel.text = "Failed"; } - if (File.Exists(tarPath)) + if (File.Exists(archivePath)) { - File.Delete(tarPath); + File.Delete(archivePath); } } @@ -380,6 +466,6 @@ private void SetCanceledStatus() private void ResetFileSizeText() { - fileSize.text = "??? MB"; + fileSize.text = "??? KB"; } } diff --git a/UltraStar Play/Assets/Scenes/Options/ContentDownload/ContentDownloadSceneUi.uxml b/UltraStar Play/Assets/Scenes/Options/ContentDownload/ContentDownloadSceneUi.uxml index 38500f9ed..295773aab 100644 --- a/UltraStar Play/Assets/Scenes/Options/ContentDownload/ContentDownloadSceneUi.uxml +++ b/UltraStar Play/Assets/Scenes/Options/ContentDownload/ContentDownloadSceneUi.uxml @@ -13,9 +13,9 @@ - + - +