(jobId, s)
| 607 | } |
| 608 | |
| 609 | function _onExtractState(jobId, s) { |
| 610 | if (!state.extractJob || state.extractJob.id !== jobId) return false; |
| 611 | state.extractJob.status = s.status; |
| 612 | state.extractJob.progress = s.progress || 0; |
| 613 | state.extractJob.stage = s.stage || s.status; |
| 614 | if (state.tab === "extract") render(); |
| 615 | if (s.status === "done" || s.status === "error" || s.status === "cancelled") { |
| 616 | if (s.status === "done") { toast("Stems ready!"); loadLibrary(); } |
| 617 | else if (s.status === "error") toast("Extraction failed."); |
| 618 | const finishedId = jobId; |
| 619 | setTimeout(() => { |
| 620 | if (state.extractJob && state.extractJob.id === finishedId) { |
| 621 | state.extractJob = null; |
| 622 | if (state.tab === "extract") render(); |
| 623 | } |
| 624 | }, 4000); |
| 625 | return true; // terminal |
| 626 | } |
| 627 | return false; |
| 628 | } |
| 629 | |
| 630 | // SSE with a REST-poll fallback (mirrors the desktop's resilience, simplified). |
| 631 | function followExtraction(jobId) { |
no test coverage detected