69752bd6a2
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/claude-agent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
158 lines
4.8 KiB
Plaintext
158 lines
4.8 KiB
Plaintext
@startuml MonitorAlbumStream - Manual Mode Happy Path
|
|
skinparam sequenceMessageAlign center
|
|
skinparam responseMessageBelowArrow true
|
|
title MonitorAlbumStream: Manual Mode (Interactive Prompts)
|
|
|
|
actor Client
|
|
participant "gRPC Server" as Server
|
|
participant "monitorWorkflow" as Workflow
|
|
participant "MusicAgregatorService" as Service
|
|
database "PostgreSQL" as DB
|
|
participant "IndexerService" as Indexer
|
|
participant "MagnetResolver" as Magnet
|
|
participant "TorrentClient\n(qBittorrent)" as QBit
|
|
|
|
== 1. Initialize Stream ==
|
|
|
|
Client -> Server: MonitorAlbumStream()
|
|
Server -> Client: stream established
|
|
|
|
Client -> Server: StartMonitorRequest
|
|
note right: album_id, quality\nmode = MANUAL
|
|
|
|
Server -> Workflow: newMonitorWorkflow()
|
|
|
|
== 2. Fetch Metadata ==
|
|
|
|
Workflow ->> Client: StatusUpdate(FETCHING_METADATA)
|
|
note right #lightblue: "Fetching album metadata..."
|
|
Workflow -> Service: getAlbumWithPersist()
|
|
Workflow ->> Client: StatusUpdate(FETCHING_METADATA)
|
|
note right #lightblue: Data: StreamAlbumInfo\n{artist, title, release_date,\nalready_owned, owned_quality}
|
|
|
|
== 3. Check Ownership (Interactive) ==
|
|
|
|
Workflow -> DB: downloads.HasAlbumInQuality()
|
|
DB --> Workflow: true (already owned!)
|
|
|
|
Workflow ->> Client: StatusUpdate(CHECKING_OWNED)
|
|
note right #lightyellow: "Already owned in FLAC quality"
|
|
|
|
Workflow ->> Client: PromptForDecision
|
|
note right #orange: type: CONFIRM\nmessage: "Album already owned. Download anyway?"\ndefault: false\ntimeout: max 300s
|
|
|
|
Client -> Server: UserDecision
|
|
note right: confirm: true\n(user chooses to continue)
|
|
|
|
Workflow -> Workflow: Continue with search
|
|
|
|
== 4. Search & Parse ==
|
|
|
|
Workflow ->> Client: StatusUpdate(SEARCHING_INDEXER)
|
|
Workflow -> Indexer: Search()
|
|
Indexer --> Workflow: 3 results
|
|
|
|
loop parse results
|
|
Workflow -> Magnet: Resolve()
|
|
end
|
|
|
|
Workflow ->> Client: StatusUpdate(PARSING_RESULTS)
|
|
note right #lightblue: Data: TorrentList\n[{id, title, seeders, format}, ...]
|
|
|
|
== 5. Select Torrents (Interactive) ==
|
|
|
|
Workflow ->> Client: PromptForDecision
|
|
note right #orange: type: SELECT_MANY\nmessage: "Select torrents to consider"\noptions: [{id, label, description}, ...]\ndefault: all selected\nmin: 1, max: N
|
|
|
|
Client -> Server: UserDecision
|
|
note right: selected_ids: ["torrent-0", "torrent-2"]\n(user deselects torrent-1)
|
|
|
|
Workflow -> Workflow: Filter to selected torrents
|
|
|
|
== 6. Filter by Quality ==
|
|
|
|
Workflow ->> Client: StatusUpdate(FILTERING_QUALITY)
|
|
Workflow -> Workflow: filterByQuality()
|
|
note right: 2 releases remain\nafter quality filter
|
|
|
|
== 7. Select Release (Interactive) ==
|
|
|
|
Workflow ->> Client: PromptForDecision
|
|
note right #orange: type: SELECT_ONE\nmessage: "Select release"\noptions: [{id, label, description}, ...]\ndefault: highest seeders
|
|
|
|
Client -> Server: UserDecision
|
|
note right: selected_id: "release-1"\n(user picks specific release)
|
|
|
|
Workflow ->> Client: StatusUpdate(SELECTING_RELEASE)
|
|
note right #lightblue: Data: ReleaseInfo\n{hash, format, seeders, tracker}
|
|
|
|
== 8. Confirm Add (Interactive) ==
|
|
|
|
Workflow ->> Client: StatusUpdate(ADDING_TORRENT)
|
|
note right #lightyellow: "Adding torrent: Title..."
|
|
|
|
Workflow ->> Client: PromptForDecision
|
|
note right #orange: type: CONFIRM\nmessage: "Add torrent 'Title' to client?"\nconfirm_label: "Add"\ncancel_label: "Skip"\ndefault: true
|
|
|
|
Client -> Server: UserDecision
|
|
note right: confirm: true
|
|
|
|
== 9. Add & Save ==
|
|
|
|
Workflow -> QBit: AddMagnet()
|
|
QBit --> Workflow: OK
|
|
|
|
Workflow ->> Client: StatusUpdate(SAVING)
|
|
Workflow -> DB: Create torrent & download
|
|
|
|
== 10. Complete ==
|
|
|
|
Workflow ->> Client: StatusUpdate(COMPLETE)
|
|
note right #lightblue: "Download started"
|
|
|
|
Workflow ->> Client: MonitorAlbumResponse
|
|
note right #lightgreen: Final result
|
|
|
|
== Cancel Cleanup (Disconnect or Cancel Message) ==
|
|
|
|
note over Client, QBit #salmon
|
|
**Manual Mode: Disconnect = Cancel**
|
|
|
|
When client disconnects or sends CancelRequest:
|
|
1. Workflow context is cancelled (stops further processing)
|
|
2. If torrent was added to qBit: **DeleteTorrent(hash)** removes it + files
|
|
3. If download record exists: marked as **cancelled** in DB
|
|
4. workflow_run marked as **cancelled** in DB
|
|
5. All events persisted to album_events for audit trail
|
|
|
|
Cleanup uses a fresh context (not the cancelled one).
|
|
end note
|
|
|
|
== Decision Points Summary ==
|
|
|
|
note over Client, QBit #lightyellow
|
|
**Manual Mode Decision Points:**
|
|
|
|
1. **CHECKING_OWNED** (CONFIRM)
|
|
- Triggered when: Album already owned in requested quality
|
|
- Default: false (skip)
|
|
- Timeout action: Use default
|
|
|
|
2. **PARSING_RESULTS** (SELECT_MANY)
|
|
- Triggered when: Multiple torrents found (>1)
|
|
- Default: All selected
|
|
- Timeout action: Use defaults
|
|
|
|
3. **SELECTING_RELEASE** (SELECT_ONE)
|
|
- Triggered when: Multiple releases after quality filter (>1)
|
|
- Default: Highest seeders
|
|
- Timeout action: Use default
|
|
|
|
4. **ADDING_TORRENT** (CONFIRM)
|
|
- Triggered: Always in manual mode
|
|
- Default: true (add)
|
|
- Timeout action: Use default
|
|
end note
|
|
|
|
@enduml
|