Repository navigation
Let an imported audio file be split again - #646
Merged
Merged
Conversation
Pressing Split stems on a track imported from a file threw an error and left the button reading "Process" for the rest of the session. The same press on a YouTube track worked. Three separate faults, all reported together in #635. Opening a track writes its source back into the composer. For a link that is a URL the button can submit. For an upload the source is the synthetic "local:my song.mp3", and stripping the prefix put the bare filename in the box: pressing the button POSTed "my song.mp3" as though it were a link. Being non-empty is also what carried it past the browser's own required check. The composer now holds only something that can actually be imported. setSubmitProcessing restored t("job.process") -- "Process" -- while index.html starts the button as t("process.splitStems"). The first submit of a session therefore renamed the button for good, on a successful import as much as on a failed one, and nothing put it back short of a reload. The third fault is the one behind the other two: the button acted on the composer, not on the track. For an upload there was nothing it could act on at all, because the source file is deleted once separation finishes. That deletion is the bulk of disk reclaim per job, but only a job that can fetch its source again may give it up: a link costs a re-download, an upload costs the recording. Uploads now keep theirs, and POST /api/jobs/{id}/resplit separates one again from it. The button aims at the open track whenever the composer has nothing to submit, and a pill in the composer names the track so it is clear what will be split. A staged file or a typed URL is still a new import and wins. The re-split produces a new job, the way re-importing a link does. Its source is deliberately not the one it was asked with: the library replaces any existing track sharing a sourceUrl, so reusing it deleted the very track the re-split came from and left that job on disk with nothing referencing it, for syncWithServer to re-adopt as a duplicate. The marker goes before the extension, since deriveQuality reads the suffix to tell a lossless WAV from a compressed MP3. Costs a decision worth stating: every uploaded track now retains its source, 100-300 MB each, where before only the stems survived. The button's label does not change. What it does is the same thing it always did.
thcp
marked this pull request as ready for review
September 21, 2026 08:11
The code quality check caught a real inconsistency: this file reaches for app.api.jobs as `jobs_mod` in six places, and the source-naming test I added imported a name from it directly instead. Two styles for one module in one file. Follows what was already here rather than converting the six.
2 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #635
Thanks to @wastedbits for the report, and for separating the error from the usability point. The two turned out to have the same cause.
Pressing Split stems on a track imported from a file threw an error and left the button reading "Process" for the rest of the session. The same press on a YouTube track worked. Three faults, reported together.
The composer held something it could never submit
Opening a track writes its source back into the composer. For a link that is a URL the button can act on. For an upload the source is the synthetic
local:my song.mp3, and stripping the prefix put the bare filename in the box, so pressing the button POSTedmy song.mp3as though it were a link. Non-empty is also what carried it past the browser's ownrequiredcheck.The box now holds only something importable, and one predicate answers "can this be fetched again" for both the composer and the re-import of an unavailable track. It existed in three spellings and they had stopped agreeing.
The button renamed itself permanently
setSubmitProcessingrestoredt("job.process")whileindex.htmlstarts the button ast("process.splitStems"). The first submit of a session renamed it for good, on a successful import as much as a failed one.The real one: the button acted on the composer, not on the track
For an upload there was nothing to act on at all, because the source file is deleted once separation finishes.
That deletion is the bulk of disk reclaim per job, but only a job that can fetch its source again may give it up. A link costs a re-download; an upload costs the recording, and the person who imported it may no longer have the file. Uploads now keep their source, and
POST /api/jobs/{id}/resplitseparates one again from it.The button aims at the open track whenever the composer has nothing to submit, and a pill in the composer names that track so it is clear what will be split. A staged file or a typed URL is still a new import and wins.
The label does not change. What the button does is the same thing it always did; only where it reads the track from differs.
Worth review: the source of the new job
A re-split produces a new job, the way re-importing a link does. Its source is deliberately not the one it was asked with.
addTrackToLibraryreplaces any existing track sharing asourceUrl. Reusing the original's deleted the very track the re-split came from, and left that job on disk with nothing referencing it, whichsyncWithServerthen re-adopts as a duplicate on the next launch. I found this by asserting the original was still in the library after a re-split, and it was not.Giving the pair the same row is not an option either: two jobs sharing a source are collapsed again on every launch, so they have to differ on disk rather than just in one session. The marker goes before the extension, since
deriveQualityreads the suffix to tell a lossless WAV from a compressed MP3.The cost, stated plainly
Every uploaded track now retains its source, 100-300 MB each, where before only the stems survived. That is the price of being able to split an imported file a second time at all.
Testing
Full local gate:
ruff check,ruff format --check,pytest1074 passed,npx playwright test181 passed,npm run test:jsclean,node --checkover every module, bandit clean at medium and above,uv.lockuntouched, i18n coverage clean. No Rust in the diff.New coverage:
source.*with an extension the importer would never accept, and crafted job ids that must be turned away before any filesystem access rather than 500.cleanup_sourcerun and asserts on the file: upload keeps it, link loses it, no recorded source loses it./resplit, one that a typed URL still wins, and the one above that the original track survives.Verified by hand on macOS against a real import as well as in CI.