Skip to content

Commit 712c54f

Browse files
Improved album art handling
Fetch album covers concurrently on the cover art tab. Resizing of embedded art now uses the 'maxAlbumArtSize' setting to stay within bounds.
1 parent 380fb2e commit 712c54f

File tree

9 files changed

+72
-26
lines changed

9 files changed

+72
-26
lines changed

CUERipper.Avalonia/Configuration/Abstractions/ICUEConfigFacade.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public interface ICUEConfigFacade
5757
bool CreateEACLog { get; set; }
5858
bool CreateM3U { get; set; }
5959
bool EmbedAlbumArt { get; set; }
60+
int MaxAlbumArtSize { get; set; }
6061
bool EjectAfterRip { get; set; }
6162
bool DisableEjectDisc { get; set; }
6263
string TrackFilenameFormat { get; set; }

CUERipper.Avalonia/Configuration/CUEConfigFacade.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public class CUEConfigFacade : ICUEConfigFacade
6868
public bool CreateEACLog { get => _cueConfig.createEACLOG; set => _cueConfig.createEACLOG = value; }
6969
public bool CreateM3U { get => _cueConfig.createM3U; set => _cueConfig.createM3U = value; }
7070
public bool EmbedAlbumArt { get => _cueConfig.embedAlbumArt; set => _cueConfig.embedAlbumArt = value; }
71+
public int MaxAlbumArtSize { get => _cueConfig.maxAlbumArtSize; set => _cueConfig.maxAlbumArtSize = value; }
7172
public bool EjectAfterRip { get => _cueConfig.ejectAfterRip; set => _cueConfig.ejectAfterRip = value; }
7273
public bool DisableEjectDisc { get => _cueConfig.disableEjectDisc; set => _cueConfig.disableEjectDisc = value; }
7374
public string TrackFilenameFormat { get => _cueConfig.trackFilenameFormat; set => _cueConfig.trackFilenameFormat = value; }

CUERipper.Avalonia/Constants.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,19 @@ public static class Constants
4141
$"%music%/%artist%/[%year% - ]%album%[ '('disc %discnumberandname%')'][' ('%releasedateandlabel%')'][' ('%unique%')']/%artist% - %album%{CueExtension}"
4242
];
4343
public const int MaxPathFormats = 10; // Based on the original CUERipper limit
44-
44+
4545
public const string ApplicationName = $"CUERipper.Avalonia {CUESheet.CUEToolsVersion}";
4646

4747
public const string PathNoto = "avares://CUERipper.Avalonia/Assets/noto-emoji/32/";
4848
public const string PathImageCache = "./CUERipper/.AlbumCache/";
4949
public const string PathUpdate = "./.cueupdate/";
5050

51-
public const int EmbeddedImageMaxDimension = 500;
5251
public const int HiResImageMaxDimension = 2048;
5352

5453
public const string GithubApiUri = "https://api.github.com/repos/gchudov/cuetools.net/releases";
5554
public const string UserAgent = "Mozilla/5.0";
5655
public const string UpdaterExecutable = "CUETools.Updater.exe";
56+
57+
public const int MaxCoverFetchConcurrency = 4;
5758
}
5859
}

CUERipper.Avalonia/Services/CUERipperService.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -407,10 +407,10 @@ public Task RipAudioTracks(RipSettings ripSettings, CancellationToken ct)
407407
if (albumCover != null)
408408
{
409409
Bitmap? embeddedArtwork = null;
410-
if (albumCover.PixelSize.Width > Constants.EmbeddedImageMaxDimension
411-
|| albumCover.PixelSize.Height > Constants.EmbeddedImageMaxDimension)
410+
if (albumCover.PixelSize.Width > _config.MaxAlbumArtSize
411+
|| albumCover.PixelSize.Height > _config.MaxAlbumArtSize)
412412
{
413-
embeddedArtwork = albumCover.ContainedResize(Constants.EmbeddedImageMaxDimension);
413+
embeddedArtwork = albumCover.ContainedResize(_config.MaxAlbumArtSize);
414414
}
415415

416416
byte[] byteArray = [];

CUERipper.Avalonia/ViewModels/Bindings/OptionProxies/Abstractions/OptionProxy.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public abstract class OptionProxy<T> : IOptionProxy
3535

3636
protected abstract string GetStringFromValue(T val);
3737
protected abstract T GetValueFromString(string str);
38+
protected virtual T ContainWithinRange(T value) => value;
3839

3940
private string _viewValue = string.Empty;
4041
public string Value
@@ -57,11 +58,13 @@ public string Value
5758
set
5859
{
5960
if (value == null || IsReadOnly) return;
60-
_viewValue = value;
6161

6262
try
6363
{
64-
T actualValue = GetValueFromString(_viewValue);
64+
T actualValue = GetValueFromString(value);
65+
actualValue = ContainWithinRange(actualValue);
66+
67+
_viewValue = GetStringFromValue(actualValue);
6568
Accessor.Set(actualValue);
6669
}
6770
catch (TypeInitializationException ex)

CUERipper.Avalonia/ViewModels/Bindings/OptionProxies/IntOptionProxy.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,38 @@ You should have received a copy of the GNU General Public License along
1616
with this program; if not, see <https://www.gnu.org/licenses/>.
1717
*/
1818
#endregion
19+
using CUERipper.Avalonia.Compatibility;
1920
using CUERipper.Avalonia.Utilities;
2021
using CUERipper.Avalonia.ViewModels.Bindings.OptionProxies.Abstractions;
2122

2223
namespace CUERipper.Avalonia.ViewModels.Bindings.OptionProxies
2324
{
2425
public class IntOptionProxy : OptionProxy<int>
2526
{
27+
private readonly int? _minValue;
28+
private readonly int? _maxValue;
29+
2630
public IntOptionProxy(string name, int defaultValue, Accessor<int> accessor)
2731
: base(name, defaultValue, accessor)
2832
{
2933
}
3034

35+
public IntOptionProxy(string name, int defaultValue, int minValue, int maxValue, Accessor<int> accessor)
36+
: base(name, defaultValue, accessor)
37+
{
38+
_minValue = minValue;
39+
_maxValue = maxValue;
40+
}
41+
3142
protected override string GetStringFromValue(int val)
3243
=> val.ToString();
3344

3445
protected override int GetValueFromString(string str)
3546
=> int.TryParse(str, out int result) ? result : Default;
47+
48+
protected override int ContainWithinRange(int val)
49+
=> _minValue != null && _maxValue != null
50+
? MathClamp.Clamp(val, _minValue.Value, _maxValue.Value)
51+
: val;
3652
}
3753
}

CUERipper.Avalonia/Views/OptionsDialog.axaml.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ private void OnDataContextChanged(object? sender, EventArgs e)
6969
, new(() => Config.CreateM3U))
7070
, new BoolOptionProxy("Embed album art", true
7171
, new(() => Config.EmbedAlbumArt))
72+
, new IntOptionProxy("Max album art size"
73+
, defaultValue: CUEConfig.Constants.MaxAlbumArtSize
74+
, minValue: CUEConfig.Constants.MaxAlbumArtSizeLowerBound
75+
, maxValue: CUEConfig.Constants.MaxAlbumArtSizeUpperBound
76+
, new(() => Config.MaxAlbumArtSize))
7277
, new BoolOptionProxy("Eject after rip", false
7378
, new(() => Config.EjectAfterRip))
7479
, new BoolOptionProxy("Disable eject disc", true
@@ -86,7 +91,10 @@ private void OnDataContextChanged(object? sender, EventArgs e)
8691
, new(() => Config.UseProxyMode))
8792
, new StringOptionProxy("Host", "127.0.0.1"
8893
, new(() => Config.ProxyServer))
89-
, new IntOptionProxy("Port", 8080
94+
, new IntOptionProxy("Port"
95+
, defaultValue: 8080
96+
, minValue: 0
97+
, maxValue: 65535
9098
, new(() => Config.ProxyPort))
9199
, new StringOptionProxy("Auth user", string.Empty
92100
, new(() => Config.ProxyUser))

CUERipper.Avalonia/Views/UserControls/CoverViewer.axaml.cs

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,26 +76,35 @@ public void Feed()
7676

7777
_thumbnailJob.Run(async (CancellationToken ct) =>
7878
{
79-
foreach (var cover in albumCovers)
79+
using var semaphore = new SemaphoreSlim(Constants.MaxCoverFetchConcurrency);
80+
await Task.WhenAll(albumCovers.Select(async cover =>
8081
{
81-
var bitmap = await _metaService.FetchImageAsync(cover.Uri150, ct);
82-
if (ct.IsCancellationRequested) break;
83-
84-
if (bitmap != null)
82+
await semaphore.WaitAsync(ct);
83+
try
8584
{
86-
cover.Bitmap150 = bitmap;
87-
Dispatcher.UIThread.Post(() =>
85+
var bitmap = await _metaService.FetchImageAsync(cover.Uri150, ct);
86+
if (ct.IsCancellationRequested) return;
87+
88+
if (bitmap != null)
8889
{
89-
if (ViewModel.AlbumCovers.None())
90+
cover.Bitmap150 = bitmap;
91+
Dispatcher.UIThread.Post(() =>
9092
{
91-
cover.IsSelected = true;
92-
ViewModel.CurrentCover = cover.Bitmap150;
93-
}
94-
95-
ViewModel.AlbumCovers.Add(cover);
96-
});
93+
if (ViewModel.AlbumCovers.None())
94+
{
95+
cover.IsSelected = true;
96+
ViewModel.CurrentCover = cover.Bitmap150;
97+
}
98+
99+
ViewModel.AlbumCovers.Add(cover);
100+
});
101+
}
102+
}
103+
finally
104+
{
105+
semaphore.Release();
97106
}
98-
}
107+
}));
99108
});
100109
}
101110

CUETools.Processor/CUEConfig.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System.Net;
55
using System.Text;
66
using System.Threading;
7-
using System.Xml;
87
using CUETools.Codecs;
98
using CUETools.Processor.Settings;
109
using Newtonsoft.Json;
@@ -14,6 +13,13 @@ namespace CUETools.Processor
1413
{
1514
public class CUEConfig
1615
{
16+
public static class Constants
17+
{
18+
public const int MaxAlbumArtSize = 300;
19+
public const int MaxAlbumArtSizeLowerBound = 100;
20+
public const int MaxAlbumArtSizeUpperBound = 10000;
21+
}
22+
1723
public uint fixOffsetMinimumConfidence;
1824
public uint fixOffsetMinimumTracksPercent;
1925
public uint encodeWhenConfidence;
@@ -138,7 +144,7 @@ public CUEConfig()
138144
CopyAlbumArt = true;
139145
embedAlbumArt = true;
140146
extractAlbumArt = true;
141-
maxAlbumArtSize = 300;
147+
maxAlbumArtSize = Constants.MaxAlbumArtSize;
142148

143149
arLogToSourceFolder = false;
144150
arLogVerbose = true;
@@ -425,7 +431,8 @@ public void Load(SettingsReader sr)
425431
CopyAlbumArt = sr.LoadBoolean("CopyAlbumArt") ?? true;
426432
embedAlbumArt = sr.LoadBoolean("EmbedAlbumArt") ?? true;
427433
extractAlbumArt = sr.LoadBoolean("ExtractAlbumArt") ?? true;
428-
maxAlbumArtSize = sr.LoadInt32("MaxAlbumArtSize", 100, 10000) ?? maxAlbumArtSize;
434+
maxAlbumArtSize = sr.LoadInt32("MaxAlbumArtSize", Constants.MaxAlbumArtSizeLowerBound, Constants.MaxAlbumArtSizeUpperBound)
435+
?? maxAlbumArtSize;
429436

430437
arLogToSourceFolder = sr.LoadBoolean("ArLogToSourceFolder") ?? arLogToSourceFolder;
431438
arLogVerbose = sr.LoadBoolean("ArLogVerbose") ?? arLogVerbose;

0 commit comments

Comments
 (0)