Skip to content

Commit 186da12

Browse files
committed
fix: on-complete index updates
1 parent ce95cf6 commit 186da12

14 files changed

Lines changed: 499 additions & 54 deletions

File tree

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -522,20 +522,17 @@ When passing an on-complete action on the command line, quote the whole value so
522522
- `when=already-exists` - Execute only for already-existing skipped jobs
523523
- `when=not-found-last-time` - Execute only for not-found-last-time skipped jobs
524524
- `when=cancelled` - Execute only for cancelled jobs
525-
- `when=partial` - Execute only for partially successful container jobs
526525
- `when=completed` - Execute for all non-skipped terminal outcomes
527526
- `when=any` - Execute for every terminal outcome
528527
- `scope=track` - Execute only for track-level completions
529528
- `scope=album` - Execute only for album-level completions
530529
- `hidden` - Hide the command window
531530
- `shell` - Use shell execute
532531
- `lock` - Serialize this action across jobs
533-
- `update-index` - Use stdout to update the index and playlist path
532+
- `update-index` - Read stdout as `success;new_path`, `failed`, or `ignored;new_path` to update the track/album entry in the index and playlist. `failed` clears the stored path; `ignored;new_path` leaves the state unchanged and updates only the path.
534533

535534
If `when=` is omitted, it behaves like `when=completed`. This preserves the usual "run when work completed" behavior while avoiding commands for already-existing or not-found-last-time skips.
536535

537-
Sockseek captures bounded stdout/stderr for ordinary on-complete commands, so chained commands can use output variables without an extra option. Commands launched with `shell` use shell execute and cannot expose stdout/stderr. When using `update-index`, stdout should be `ignored;new_path` to update the track path in the index and playlist.
538-
539536
### Variables
540537

541538
The available variables are the same as in [name-format](#available-variables), with the following additions:
@@ -546,6 +543,8 @@ The available variables are the same as in [name-format](#available-variables),
546543
- `{first-stdout}` - First command's stdout
547544
- `{first-stderr}` - First command's stderr
548545

546+
Sockseek captures bounded stdout/stderr for ordinary on-complete commands, so chained commands can use output variables from the previous ones. Commands launched with `shell` use shell execute and cannot expose stdout/stderr.
547+
549548
For album-only (`scope=album`) actions, tag variables such as `{title}`, `{artist}`, and `{album}` are read from the first audio file in the album. Job/source/path variables such as `{sartist}`, `{salbum}`, and `{path}` describe the album-level completion itself.
550549

551550
### Examples

Sockseek.Cli/Help.Content.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -604,21 +604,18 @@ after it is the command passed to the operating system.
604604
- when=already-exists - Execute only for already-existing skipped jobs
605605
- when=not-found-last-time - Execute only for not-found-last-time skipped jobs
606606
- when=cancelled - Execute only for cancelled jobs
607-
- when=partial - Execute only for partially successful container jobs
608607
- when=completed - Execute for all non-skipped terminal outcomes
609608
- when=any - Execute for every terminal outcome
610609
- scope=track - Execute only for track-level completions
611610
- scope=album - Execute only for album-level completions
612611
- hidden - Hide the command window
613612
- shell - Use shell execute
614613
- lock - Serialize this action across jobs
615-
- update-index - Use stdout to update the index and playlist path
614+
- update-index - Read stdout as success;new_path, failed, or ignored;new_path to update the
615+
track/album entry in the index and playlist. failed clears the stored path; ignored;new_path
616+
leaves the state unchanged and updates only the path.
616617
If when= is omitted, it behaves like when=completed. This preserves the usual ""run when work
617618
completed"" behavior while avoiding commands for already-existing or not-found-last-time skips.
618-
Sockseek captures bounded stdout/stderr for ordinary on-complete commands, so chained commands
619-
can use output variables without an extra option. Commands launched with shell use shell execute
620-
and cannot expose stdout/stderr. When using update-index, stdout should be ignored;new_path to
621-
update the track path in the index and playlist.
622619
623620
Variables
624621
The available variables are the same as in name-format, with the following additions:
@@ -628,6 +625,9 @@ update the track path in the index and playlist.
628625
- {first-exitcode} - First command's exit code
629626
- {first-stdout} - First command's stdout
630627
- {first-stderr} - First command's stderr
628+
Sockseek captures bounded stdout/stderr for ordinary on-complete commands, so chained commands
629+
can use output variables from the previous ones. Commands launched with shell use shell execute
630+
and cannot expose stdout/stderr.
631631
For album-only (scope=album) actions, tag variables such as {title}, {artist}, and {album} are
632632
read from the first audio file in the album. Job/source/path variables such as {sartist},
633633
{salbum}, and {path} describe the album-level completion itself.

Sockseek.Core.Tests/IndexTests.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,32 @@ public void Index_IndexRoundTrip_PreservesData()
112112
Assert.IsNull(prev3);
113113
}
114114

115+
[TestMethod]
116+
public void Index_FailedJobWithClearedPath_UpdatesExistingPathToEmpty()
117+
{
118+
var song = new SongJob(new SongQuery { Artist = "Artist", Title = "Title" });
119+
song.SetDone();
120+
song.DownloadPath = "path/to/file.mp3";
121+
122+
var (queue, _, _) = MakeSongQueue([song]);
123+
File.WriteAllText(testM3uPath, "");
124+
var editor = new M3uEditor(testM3uPath, queue, M3uOption.Index, true);
125+
editor.Update();
126+
127+
JobOutcomeCommitter.Commit(song, JobOutcome.Failed(JobFailureReason.AllDownloadsFailed, clearDownloadPath: true));
128+
editor.Update();
129+
130+
var lookup = new SongJob(new SongQuery { Artist = "Artist", Title = "Title" });
131+
var (queue2, _, _) = MakeSongQueue([lookup]);
132+
var editor2 = new M3uEditor(testM3uPath, queue2, M3uOption.Index, true);
133+
134+
editor2.TryGetPreviousRunResult(lookup, out var prev);
135+
Assert.IsNotNull(prev);
136+
Assert.AreEqual(JobStateOld.Failed, prev.State);
137+
Assert.AreEqual(JobFailureReason.AllDownloadsFailed, prev.FailureReason);
138+
Assert.AreEqual("", prev.DownloadPath);
139+
}
140+
115141
[TestMethod]
116142
public void Index_SerializesFilePathsWithForwardSlashes()
117143
{
@@ -169,6 +195,7 @@ public void Index_WithAlbumJobs_RoundTripsCorrectly()
169195
Assert.IsNotNull(prev, $"Previous run result not found for {lookupJobs[i].Query.Artist} - {lookupJobs[i].Query.Album}");
170196
Assert.AreEqual(albumJobs[i].Query.Artist, prev.Artist);
171197
Assert.AreEqual(albumJobs[i].Query.Album, prev.Album);
198+
Assert.AreEqual(albumJobs[i].DownloadPath ?? "", prev.DownloadPath);
172199

173200
// Verify prev is a separate object from the job
174201
string originalPath = albumJobs[i].DownloadPath ?? "";

0 commit comments

Comments
 (0)