Skip to content

Conversation

UnknownException
Copy link

@UnknownException UnknownException commented Mar 9, 2025

I’ve been experimenting with Avalonia and decided to use CUERipper as a test subject. The challenge of porting a .NET Framework application to Linux with Avalonia is what motivated me. What started as a curiosity-driven experiment quickly grew into a fully functional implementation rather than just a proof of concept, unintended scope creep! 🙂

The goal is to create a new UI without causing breaking changes in the existing codebase. It's targeted at .NET 8 but remains compatible with .NET 4.7, as some plugins still seem to rely on it.

I've submitted this as a draft pull request so you can decide if this is the direction you want the application to take, given the impact of the chosen UI tooling (for example, how this might affect the CUETools app.). If you're open to merging it into the main repository, I can provide it as a single PR or split it into smaller, more manageable ones (Linux support, Avalonia UI, GitHub packaging) for review.

This also comes with several new features:

  • Album cover selector
  • Multi-encoding
  • Automatic ripping
  • Repair functionality (same as in CUETools)
  • Minimal native Linux support
  • Track progress
  • In-app updater
  • Installer
  • Dark/Light theme and decent DPI scaling (Avalonia goodies!)

Feel free to try out the test build, you can find it under 'Releases' in my fork. For now I'll focus on improving the Linux build. Unit tests will be added if this PR has a chance of being merged, as they're a lot of work to write. For more information about Avalonia, see https://avaloniaui.net/

Screenshots:
Scr_Repair
Scr_Cover
Scr_LightMode

PS Purely out of curiosity, why is the EAC plugin built with .NET Framework 2.0?

Zips the files into 'CUETools.CTDB.EACPlugin' and 'CUETools' and generates SHA256 hashes for the zip-containers.
Added CHANGELOG.md to the root of the project
Added basic Linux support by porting libraries to .NET Standard 2.0.
BwgBurn's SCSI commands, originally relying on DeviceIoControl in WinDev.cs, are handled by LinDev.cs using IOCTL when running on Linux.
Windows structures are translated at runtime to their Linux counterparts, limited to what's actually used by BwgBurn.
Reimplemented most features of the original CUERipper in an Avalonia-based application, keeping the logic as close as possible to the original without introducing breaking changes.

Added new functionalities:
* Cover selector
* Output path management
* Multi-encoding
* Automatic ripping
* Repair functionality (same as in CUETools)
* Minimal native Linux support
* Track progress
* In-app updater
Enabled the Linux-specific drive detection in CUERipper.Avalonia.
Added a new release artifact, postfixed with 'Lite', which excludes CUERipper.Avalonia and the Avalonia runtime.
@c72578
Copy link
Collaborator

c72578 commented Mar 9, 2025

@UnknownException This looks impressive at first glance ...

PS Purely out of curiosity, why is the EAC plugin built with .NET Framework 2.0?

EAC contains Interop.HelperFunctionsLib.dll, which is .NET 2.0.

# Windows PowerShell
$path = "C:\Program Files (x86)\Exact Audio Copy\Interop.HelperFunctionsLib.dll"
>> [Reflection.Assembly]::ReflectionOnlyLoadFrom($path).ImageRuntimeVersion
v2.0.50727

Set 'AutomationProperties.Name' for various components.
Added a warning sound when a message box opens (.NET 4.7 only).
Fixed a bug that allowed tabbing to components outside of the visible area.
Added a warning before closing the application while ripping.
@ha-korth
Copy link

ha-korth commented Mar 9, 2025

User perspective.
Package is huge. 7x the size of Windows only package.
I know your focus is Linux for now but I did a brief test on Windows.
Album cover selector - No coverart downloaded until after the rip is started so no selection.
Edit: Album cover selector requires hitting refresh button (apparently each time) before coverart appears.
folder.jpg is reduced to 500px but you're not utilizing MaxAlbumArtSize= in settings.txt to make that user configurable. Default is MaxAlbumArtSize=300 (which is also ignored by the original CUERipper.exe)
Output path management (extended usability compared to the original) - not seeing anything new other than buttons to add, copy/edit or remove templates.
That's as far as I got so far.

@UnknownException
Copy link
Author

UnknownException commented Mar 16, 2025

@ha-korth thanks for testing and your feedback.

Calling the file size huge might be an overstatement. Yes, it's larger than the original, but it's comparable to a single FLAC track. Unlike WinForms, Avalonia isn't built into the OS, so the UI framework needs to be bundled. That said, I've also modified the GitHub workflow to create a build that excludes the Avalonia application, it's postfixed with 'Lite' for those who prefer a smaller package.

Edit: Album cover selector requires hitting refresh button (apparently each time) before coverart appears.

The cover art starts loading as soon as the disc is inserted.
You can see this in MainWindow.axaml.cs -> 'InitializeApplicationAsync', where it calls coverViewer.Feed() which retrieves images either from web or local cache. Clicking the refresh button should not be required for the images to load. So far I haven't been able to reproduce this on my machine or in a virtual machine. Images take some time to load and there's no indicator yet. Might be a bug, but I'll need more information.

folder.jpg is reduced to 500px but you're not utilizing MaxAlbumArtSize= in settings.txt to make that user configurable. Default is MaxAlbumArtSize=300 (which is also ignored by the original CUERipper.exe)

The embedded covert art is reduced to 500px because some media players (Windows Media Player) can't handle larger artwork, which'll result in the track being unplayable. Using 'MaxAlbumArtSize' instead of hardcoding makes sense, so I'll be implementing that soon. Additionally the selected cover will be downloaded as high(er) resolution image (cover_hi-res.jpg) when the ripping process starts.

Output path management (extended usability compared to the original) - not seeing anything new other than buttons to add, copy/edit or remove templates.

Fair enough, poor choice of words on my part. Other than the new buttons and the previewer it's practically the same.

Fetch album covers concurrently on the cover art tab.
Resizing of embedded art now uses the 'maxAlbumArtSize' setting to stay within bounds.
@ha-korth
Copy link

ha-korth commented Mar 16, 2025

That said, I've also modified the GitHub workflow to create a build that excludes the Avalonia application, it's postfixed with 'Lite' for those who prefer a smaller package.

If the user is going for the 'Lite' package, CUERipper.exe and CUERipper.Avalonia.exe should have the same features available (when possible). Several of the new features of Avalonia are on the CUERipper feature WishList.

The cover art starts loading as soon as the disc is inserted.

Okay I can reproduce. I have more than one optical drive. The CD was already in the drive but a different drive was active when CUERipper.Avalonia was executed. Switching drives doesn't load art without refresh. If any art was already retrieved for a CD in the first drive, it remains in the cache after selecting the second drive (until refresh).

I haven't had a chance to further explore the Windows side of CUERipper.Avalonia.

Retrieve the primary cover art before fetching additional images.
By separating the retrieval process, primary artwork will always appear first.
Add a step to build an Inno Setup-based CUETools installer in the Windows workflow.
Fixed various bugs related to switching between drives.
The in-app updater now uses the installer instead of zip file.
The updater now also caches the release author.
Modified regex patterns to allow a single letter (a-z, A-Z) after the last digit in the version string.
Users can now disable the automatic update check.
Fixed a minor bug in the Inno Setup script.
Write the cover art cache and update content to the user directory when user profiles are enabled.
@UnknownException
Copy link
Author

Okay I can reproduce. I have more than one optical drive. The CD was already in the drive but a different drive was active when CUERipper.Avalonia was executed. Switching drives doesn't load art without refresh. If any art was already retrieved for a CD in the first drive, it remains in the cache after selecting the second drive (until refresh).

@ha-korth would you be able to try the latest release (v2.2.6b)?
I've reproduced the bug to a certain extent. Since I don't have a secondary drive, I had to use a bit of trickery to make a second drive appear. I'd like to know if the issue is resolved.

@ha-korth
Copy link

I only did a quick check but appears to be working okay. I didn't expect both sets of art in the .AlbumCache folder but only relevant art appears in the Album cover selector window for each drive.

@Barough
Copy link

Barough commented Mar 20, 2025

Had to give this CueRipper Avalonia UI Edition (v2.2.6b) a try.......
Looks nice and works fine (if you dont use really new albums. Metadata and album covers didn't get downloaded)

THe only thing i noticed was that the yellow text in the Options/Proxy 'tab' isn't readable against the white backround

@UnknownException
Copy link
Author

I only did a quick check but appears to be working okay. I didn't expect both sets of art in the .AlbumCache folder but only relevant art appears in the Album cover selector window for each drive.

Thanks! The .AlbumCache folder only gets wiped when the application shuts down @ App.axaml.cs. I did that to prevent downloading the same assets over and over again from the remote host. The files are relatively small, so I don't think it'll cause an issue.

Looks nice and works fine (if you dont use really new albums. Metadata and album covers didn't get downloaded)

I'm afraid that this might be caused by this issue: gchudov/db.cue.tools#22

THe only thing i noticed was that the yellow text in the Options/Proxy 'tab' isn't readable against the white backround

Thanks! I will change it

@DuMichAuch72
Copy link

DuMichAuch72 commented Mar 21, 2025

@UnknownException
The MetadataCache for CUERipper dosn't work with the CUERipper.Avalonia. After opening CUERipper, no ripping possible with CUERipper.Avalonia. Workaround now is deleting the Cache.
EDIT: With the latest Build it is working.

Logs will now be written to the user directory if user profiles are enabled.
Renamed user agent from 'Mozilla/5.0' to the following pattern: 'ApplicationShortName/CUEToolsVersion ( github uri )'.
Changed the proxy settings warning color from yellow to orange.
@UnknownException UnknownException force-pushed the cueripper-avalonia branch 2 times, most recently from 89aa75a to a1ecded Compare March 23, 2025 10:52
@RDamman
Copy link
Contributor

RDamman commented Jun 24, 2025

Very nice what you have done. Especially the new features:

  • Repair functionality (same as in CUETools): Yes, very wanted. For most uses it's unknown or not clear how to use it.
  • Album cover selector: Yes, beautiful to have a choice
  • Minimal native Linux support: Yes, long over due.
  • In-app updater: nice.
  • Installer: nice.
  • Dark/Light theme and decent DPI scaling (Avalonia goodies!): Looks nice.
  • Multi-encoding: Less needed. With i.e. Foobar2000 you can batch convert files
  • Automatic ripping: Less needed. You always want to check the metadata.
  • Track progress: In my opinion it gives no extra info.

Only one thing is missing. It's editing and cut/copy from/to multiple cells in multiple rows in the tracklist grid. I have implemented something with the datagridview. This makes it possible to copy from/to multiple cells and/or a spreadsheet program.

afbeelding

The call to _thread.Start() was accidentally removed during development, causing the drive list to stop updating.
The DrivesAvailable function could fail when reinserting USB CD drives, as the identifying drive number can change.
The ReadSubchannel gap detection method fails on subsequent ReadSubChannel42 calls, as the position 'sPos' appears to drift.
The current workaround is to include QChannel in the read calls prior to ReadSubChannel42.
Modified CUEMetaService.cs to reuse the album lookup functionality from CUETools.Processor's CUESheet.cs
Allow the updater to check for updates on Linux, but disable downloading and installing.
The update process is currently only implemented for Windows.
The track progress indicator goes out of bounds when additional read passes are performed for error correction.
Grids for tracks and metadata have been refactored into separate components.
Both new components derive from CUEGrid, adding additional copy/paste logic which should improve the usability of the Avalonia grid.

Additionally, a bug with the album release dropdown was fixed during the refactor. The previous string comparison was too weak, resulting in incorrect matches.
The previous commit used features not supported by .NET 4.7, unintentionally breaking support.
Since the change was only tested on Linux, a bug affecting copy/paste in DataGrids on Windows slipped through.
On Windows 'KeyEventArgs.KeySymbol' doesn't return symbols as it does on Linux.
@UnknownException
Copy link
Author

UnknownException commented Jul 20, 2025

Only one thing is missing. It's editing and cut/copy from/to multiple cells in multiple rows in the tracklist grid. I have implemented something with the datagridview. This makes it possible to copy from/to multiple cells and/or a spreadsheet program.

I've now implemented similar functionality for the Avalonia DataGrid. As the DataGrid has some limitations, I had to apply a few workarounds.
Copying multiple rows works in two ways:

  • Select multiple rows, right click and choose copy range
  • When multiple rows are selected and no cell is focused (click a cell, hit CTRL + A, hit CTRL + C)
    Pasting into multiple rows works similarly.

Bulk paste into a column:

  • Select the rows you want to update and make sure the column you want to modify is focused, then paste (CTRL + V).

You can now also type directly into cells without needing to double click them first.
Please give it a try and let me know if this works for you.

Compile both libraries from source and copy the shared libraries into the x64 plugin directory.
Modify CUETools.Codecs.libFLAC and CUETools.Codecs.libmp3lame to support loading libraries on Linux.
Add a helper class 'LibraryResolver' which adds support for resolving libraries from the plugins/x64 folder.
Add release-linux.yml specifically for building CUERipper.Avalonia on Linux.
Remove the CUERipper.Avalonia build steps for Linux from release-windows.yml.
@UnknownException
Copy link
Author

libFLAC and LAME are now supported in CUERipper.Avalonia for Linux as of version 2.2.6f.
The workflows have been split for Linux and Windows to simplify building native libraries directly on their target OS.

Incorrect usage of CUEStyle.SingleFileWithCUE causes the disc repair to fail.
Check if 'allowEmbed' is set for the selected encoding, fallback to CUEStyle.SingleFile if not.
Apply minor stability and logging improvements.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants