Files
music-agregator/docs/MonitorAlbum Happy Path.svg
Alexander 758a4b909a Leftovers
2026-05-09 21:31:24 +02:00

1 line
66 KiB
XML

<?plantuml 1.2026.2?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" data-diagram-type="SEQUENCE" height="2845px" preserveAspectRatio="none" style="width:2335px;height:2845px;background:#FFFFFF;" version="1.1" viewBox="0 0 2335 2845" width="2335px" zoomAndPan="magnify"><defs/><g><rect fill="none" height="284" style="stroke:#000000;stroke-width:1.5;" width="1557.0654" x="390.2632" y="968.4453"/><rect fill="none" height="252.8672" style="stroke:#000000;stroke-width:1.5;" width="1200.7622" x="400.2632" y="992.5781"/><rect fill="none" height="90.2031" style="stroke:#000000;stroke-width:1.5;" width="1187.7593" x="400.2632" y="1503.375"/><rect fill="none" height="211.8672" style="stroke:#000000;stroke-width:1.5;" width="1285.1338" x="1033.0195" y="2521.8281"/><g class="participant-lifeline" data-entity-uid="part1" data-qualified-name="Client" id="part1-lifeline"><g><title>Client</title><rect fill="#000000" fill-opacity="0.00000" height="2667.1016" width="8" x="24.2651" y="83.5938"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5,5;" x1="28" x2="28" y1="83.5938" y2="2750.6953"/></g></g><g class="participant-lifeline" data-entity-uid="part2" data-qualified-name="Server" id="part2-lifeline"><g><title>gRPC Server</title><rect fill="#000000" fill-opacity="0.00000" height="2667.1016" width="8" x="316.0093" y="83.5938"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5,5;" x1="319.4131" x2="319.4131" y1="83.5938" y2="2750.6953"/></g></g><g class="participant-lifeline" data-entity-uid="part3" data-qualified-name="Service" id="part3-lifeline"><g><title>MusicAgregatorService</title><rect fill="#000000" fill-opacity="0.00000" height="2667.1016" width="8" x="494.105" y="83.5938"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5,5;" x1="497.2632" x2="497.2632" y1="83.5938" y2="2750.6953"/></g></g><g class="participant-lifeline" data-entity-uid="part4" data-qualified-name="Metadata" id="part4-lifeline"><g><title>MetadataService</title><rect fill="#000000" fill-opacity="0.00000" height="2667.1016" width="8" x="727.2007" y="83.5938"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5,5;" x1="731.1826" x2="731.1826" y1="83.5938" y2="2750.6953"/></g></g><g class="participant-lifeline" data-entity-uid="part5" data-qualified-name="MetaGRPC" id="part5-lifeline"><g><title>metadata-agregator</title><rect fill="#000000" fill-opacity="0.00000" height="2667.1016" width="8" x="955.0112" y="83.5938"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5,5;" x1="959.0029" x2="959.0029" y1="83.5938" y2="2750.6953"/></g></g><g class="participant-lifeline" data-entity-uid="part6" data-qualified-name="DB" id="part6-lifeline"><g><title>PostgreSQL</title><rect fill="#000000" fill-opacity="0.00000" height="2667.1016" width="8" x="1082.396" y="83.5938"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5,5;" x1="1086.0195" x2="1086.0195" y1="83.5938" y2="2750.6953"/></g></g><g class="participant-lifeline" data-entity-uid="part7" data-qualified-name="Indexer" id="part7-lifeline"><g><title>IndexerService</title><rect fill="#000000" fill-opacity="0.00000" height="2667.1016" width="8" x="1195.2212" y="83.5938"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5,5;" x1="1198.7725" x2="1198.7725" y1="83.5938" y2="2750.6953"/></g></g><g class="participant-lifeline" data-entity-uid="part8" data-qualified-name="Magnet" id="part8-lifeline"><g><title>MagnetResolver</title><rect fill="#000000" fill-opacity="0.00000" height="2667.1016" width="8" x="1394.2554" y="83.5938"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5,5;" x1="1397.623" x2="1397.623" y1="83.5938" y2="2750.6953"/></g></g><g class="participant-lifeline" data-entity-uid="part9" data-qualified-name="QBit" id="part9-lifeline"><g><title>TorrentClient</title><rect fill="#000000" fill-opacity="0.00000" height="2667.1016" width="8" x="1520.9551" y="83.5938"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5,5;" x1="1524.8877" x2="1524.8877" y1="83.5938" y2="2750.6953"/></g></g><g class="participant-lifeline" data-entity-uid="part10" data-qualified-name="River" id="part10-lifeline"><g><title>River Queue</title><rect fill="#000000" fill-opacity="0.00000" height="2667.1016" width="8" x="1634.3794" y="83.5938"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5,5;" x1="1638.0225" x2="1638.0225" y1="83.5938" y2="2750.6953"/></g></g><g class="participant-lifeline" data-entity-uid="part11" data-qualified-name="PollWorker" id="part11-lifeline"><g><title>PollDownloadWorker</title><rect fill="#000000" fill-opacity="0.00000" height="2667.1016" width="8" x="1822.7075" y="83.5938"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5,5;" x1="1826.1987" x2="1826.1987" y1="83.5938" y2="2750.6953"/></g></g><g class="participant participant-head" data-entity-uid="part1" data-qualified-name="Client" id="part1-head"><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="40.5303" x="5" y="80.292">Client</text><ellipse cx="28.2651" cy="15.7969" fill="#E2E2F0" rx="8" ry="8" style="stroke:#181818;stroke-width:0.5;"/><path d="M28.2651,23.7969 L28.2651,50.7969 M15.2651,31.7969 L41.2651,31.7969 M28.2651,50.7969 L15.2651,65.7969 M28.2651,50.7969 L41.2651,65.7969" fill="none" style="stroke:#181818;stroke-width:0.5;"/></g><g class="participant participant-tail" data-entity-uid="part1" data-qualified-name="Client" id="part1-tail"><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="40.5303" x="5" y="2762.6904">Client</text><ellipse cx="28.2651" cy="2774.4922" fill="#E2E2F0" rx="8" ry="8" style="stroke:#181818;stroke-width:0.5;"/><path d="M28.2651,2782.4922 L28.2651,2809.4922 M15.2651,2790.4922 L41.2651,2790.4922 M28.2651,2809.4922 L15.2651,2824.4922 M28.2651,2809.4922 L41.2651,2824.4922" fill="none" style="stroke:#181818;stroke-width:0.5;"/></g><g class="participant participant-head" data-entity-uid="part2" data-qualified-name="Server" id="part2-head"><rect fill="#E2E2F0" height="30.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="101.1924" x="269.4131" y="52.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="87.1924" x="276.4131" y="72.292">gRPC Server</text></g><g class="participant participant-tail" data-entity-uid="part2" data-qualified-name="Server" id="part2-tail"><rect fill="#E2E2F0" height="30.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="101.1924" x="269.4131" y="2749.6953"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="87.1924" x="276.4131" y="2769.6904">gRPC Server</text></g><g class="participant participant-head" data-entity-uid="part3" data-qualified-name="Service" id="part3-head"><rect fill="#E2E2F0" height="30.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="175.6836" x="410.2632" y="52.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="161.6836" x="417.2632" y="72.292">MusicAgregatorService</text></g><g class="participant participant-tail" data-entity-uid="part3" data-qualified-name="Service" id="part3-tail"><rect fill="#E2E2F0" height="30.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="175.6836" x="410.2632" y="2749.6953"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="161.6836" x="417.2632" y="2769.6904">MusicAgregatorService</text></g><g class="participant participant-head" data-entity-uid="part4" data-qualified-name="Metadata" id="part4-head"><rect fill="#E2E2F0" height="30.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="132.0361" x="665.1826" y="52.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="118.0361" x="672.1826" y="72.292">MetadataService</text></g><g class="participant participant-tail" data-entity-uid="part4" data-qualified-name="Metadata" id="part4-tail"><rect fill="#E2E2F0" height="30.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="132.0361" x="665.1826" y="2749.6953"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="118.0361" x="672.1826" y="2769.6904">MetadataService</text></g><g class="participant participant-head" data-entity-uid="part5" data-qualified-name="MetaGRPC" id="part5-head"><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="142.0166" x="885.0029" y="63.9951">metadata-agregator</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="47.7559" x="932.1333" y="80.292">(gRPC)</text><path d="M941.0112,15 C941.0112,5 959.0112,5 959.0112,5 C959.0112,5 977.0112,5 977.0112,15 L977.0112,41 C977.0112,51 959.0112,51 959.0112,51 C959.0112,51 941.0112,51 941.0112,41 L941.0112,15" fill="#E2E2F0" style="stroke:#181818;stroke-width:0.5;"/><path d="M941.0112,15 C941.0112,25 959.0112,25 959.0112,25 C959.0112,25 977.0112,25 977.0112,15" fill="none" style="stroke:#181818;stroke-width:0.5;"/></g><g class="participant participant-tail" data-entity-uid="part5" data-qualified-name="MetaGRPC" id="part5-tail"><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="142.0166" x="885.0029" y="2762.6904">metadata-agregator</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="47.7559" x="932.1333" y="2778.9873">(gRPC)</text><path d="M941.0112,2792.2891 C941.0112,2782.2891 959.0112,2782.2891 959.0112,2782.2891 C959.0112,2782.2891 977.0112,2782.2891 977.0112,2792.2891 L977.0112,2818.2891 C977.0112,2828.2891 959.0112,2828.2891 959.0112,2828.2891 C959.0112,2828.2891 941.0112,2828.2891 941.0112,2818.2891 L941.0112,2792.2891" fill="#E2E2F0" style="stroke:#181818;stroke-width:0.5;"/><path d="M941.0112,2792.2891 C941.0112,2802.2891 959.0112,2802.2891 959.0112,2802.2891 C959.0112,2802.2891 977.0112,2802.2891 977.0112,2792.2891" fill="none" style="stroke:#181818;stroke-width:0.5;"/></g><g class="participant participant-head" data-entity-uid="part6" data-qualified-name="DB" id="part6-head"><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="80.7529" x="1043.0195" y="80.292">PostgreSQL</text><path d="M1068.396,31.2969 C1068.396,21.2969 1086.396,21.2969 1086.396,21.2969 C1086.396,21.2969 1104.396,21.2969 1104.396,31.2969 L1104.396,57.2969 C1104.396,67.2969 1086.396,67.2969 1086.396,67.2969 C1086.396,67.2969 1068.396,67.2969 1068.396,57.2969 L1068.396,31.2969" fill="#E2E2F0" style="stroke:#181818;stroke-width:0.5;"/><path d="M1068.396,31.2969 C1068.396,41.2969 1086.396,41.2969 1086.396,41.2969 C1086.396,41.2969 1104.396,41.2969 1104.396,31.2969" fill="none" style="stroke:#181818;stroke-width:0.5;"/></g><g class="participant participant-tail" data-entity-uid="part6" data-qualified-name="DB" id="part6-tail"><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="80.7529" x="1043.0195" y="2762.6904">PostgreSQL</text><path d="M1068.396,2775.9922 C1068.396,2765.9922 1086.396,2765.9922 1086.396,2765.9922 C1086.396,2765.9922 1104.396,2765.9922 1104.396,2775.9922 L1104.396,2801.9922 C1104.396,2811.9922 1086.396,2811.9922 1086.396,2811.9922 C1086.396,2811.9922 1068.396,2811.9922 1068.396,2801.9922 L1068.396,2775.9922" fill="#E2E2F0" style="stroke:#181818;stroke-width:0.5;"/><path d="M1068.396,2775.9922 C1068.396,2785.9922 1086.396,2785.9922 1086.396,2785.9922 C1086.396,2785.9922 1104.396,2785.9922 1104.396,2775.9922" fill="none" style="stroke:#181818;stroke-width:0.5;"/></g><g class="participant participant-head" data-entity-uid="part7" data-qualified-name="Indexer" id="part7-head"><rect fill="#E2E2F0" height="46.5938" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="118.8975" x="1139.7725" y="36"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="104.8975" x="1146.7725" y="55.9951">IndexerService</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="59.0283" x="1169.707" y="72.292">(Jackett)</text></g><g class="participant participant-tail" data-entity-uid="part7" data-qualified-name="Indexer" id="part7-tail"><rect fill="#E2E2F0" height="46.5938" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="118.8975" x="1139.7725" y="2749.6953"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="104.8975" x="1146.7725" y="2769.6904">IndexerService</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="59.0283" x="1169.707" y="2785.9873">(Jackett)</text></g><g class="participant participant-head" data-entity-uid="part8" data-qualified-name="Magnet" id="part8-head"><rect fill="#E2E2F0" height="30.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="127.2646" x="1334.623" y="52.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="113.2646" x="1341.623" y="72.292">MagnetResolver</text></g><g class="participant participant-tail" data-entity-uid="part8" data-qualified-name="Magnet" id="part8-tail"><rect fill="#E2E2F0" height="30.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="127.2646" x="1334.623" y="2749.6953"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="113.2646" x="1341.623" y="2769.6904">MagnetResolver</text></g><g class="participant participant-head" data-entity-uid="part9" data-qualified-name="QBit" id="part9-head"><rect fill="#E2E2F0" height="46.5938" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="106.1348" x="1471.8877" y="36"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="92.1348" x="1478.8877" y="55.9951">TorrentClient</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="87.3359" x="1481.2871" y="72.292">(qBittorrent)</text></g><g class="participant participant-tail" data-entity-uid="part9" data-qualified-name="QBit" id="part9-tail"><rect fill="#E2E2F0" height="46.5938" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="106.1348" x="1471.8877" y="2749.6953"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="92.1348" x="1478.8877" y="2769.6904">TorrentClient</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="87.3359" x="1481.2871" y="2785.9873">(qBittorrent)</text></g><g class="participant participant-head" data-entity-uid="part10" data-qualified-name="River" id="part10-head"><rect fill="#E2E2F0" height="30.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="100.7139" x="1588.0225" y="52.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="86.7139" x="1595.0225" y="72.292">River Queue</text></g><g class="participant participant-tail" data-entity-uid="part10" data-qualified-name="River" id="part10-tail"><rect fill="#E2E2F0" height="30.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="100.7139" x="1588.0225" y="2749.6953"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="86.7139" x="1595.0225" y="2769.6904">River Queue</text></g><g class="participant participant-head" data-entity-uid="part11" data-qualified-name="PollWorker" id="part11-head"><rect fill="#E2E2F0" height="30.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="159.0176" x="1747.1987" y="52.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="145.0176" x="1754.1987" y="72.292">PollDownloadWorker</text></g><g class="participant participant-tail" data-entity-uid="part11" data-qualified-name="PollWorker" id="part11-tail"><rect fill="#E2E2F0" height="30.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="159.0176" x="1747.1987" y="2749.6953"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="145.0176" x="1754.1987" y="2769.6904">PollDownloadWorker</text></g><rect fill="#EEEEEE" height="3" style="stroke:#EEEEEE;stroke-width:1;" width="2328.1533" x="0" y="114.1602"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="114.1602" y2="114.1602"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="117.1602" y2="117.1602"/><rect fill="#EEEEEE" height="23.1328" style="stroke:#000000;stroke-width:2;" width="203.3887" x="1062.3823" y="103.5938"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="184.8628" x="1068.3823" y="119.6606">1. Fetch Album Metadata</text><g class="message" data-entity-1="part1" data-entity-2="part2" id="msg1"><polygon fill="#181818" points="308.0093,153.8594,318.0093,157.8594,308.0093,161.8594,312.0093,157.8594" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="28.2651" x2="314.0093" y1="157.8594" y2="157.8594"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="267.7441" x="40.2651" y="152.7935">MonitorAlbum(album_id, quality, tracker)</text></g><g class="message" data-entity-1="part2" data-entity-2="part3" id="msg2"><polygon fill="#181818" points="486.105,182.9922,496.105,186.9922,486.105,190.9922,490.105,186.9922" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="320.0093" x2="492.105" y1="186.9922" y2="186.9922"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="151.0171" x="333.5486" y="181.9263">MonitorAlbum(ctx, req)</text></g><g class="message" data-entity-1="part3" data-entity-2="part4" id="msg3"><polygon fill="#181818" points="719.2007,212.125,729.2007,216.125,719.2007,220.125,723.2007,216.125" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="725.2007" y1="216.125" y2="216.125"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="134.0688" x="547.6184" y="211.0591">GetAlbum(album_id)</text></g><g class="message" data-entity-1="part4" data-entity-2="part5" id="msg4"><polygon fill="#181818" points="947.0112,241.2578,957.0112,245.2578,947.0112,249.2578,951.0112,245.2578" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="731.2007" x2="953.0112" y1="245.2578" y2="245.2578"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="86.8359" x="801.688" y="240.1919">GetAlbum(id)</text></g><g class="message" data-entity-1="part5" data-entity-2="part4" id="msg5"><polygon fill="#181818" points="742.2007,270.3906,732.2007,274.3906,742.2007,278.3906,738.2007,274.3906" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="736.2007" x2="958.0112" y1="274.3906" y2="274.3906"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="203.8105" x="743.2007" y="269.3247">Album (title, artists, genres, ...)</text></g><g class="message" data-entity-1="part4" data-entity-2="part6" id="msg6"><polygon fill="#181818" points="1074.396,302.5234,1084.396,306.5234,1074.396,310.5234,1078.396,306.5234" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="731.2007" x2="1080.396" y1="306.5234" y2="306.5234"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="241.8838" x="787.8564" y="301.4575">albums.GetByExternalID(external_id)</text></g><path d="M1091,287.3906 L1091,312.3906 L1326,312.3906 L1326,297.3906 L1316,287.3906 L1091,287.3906" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M1316,287.3906 L1316,297.3906 L1326,297.3906 L1316,287.3906" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="214.373" x="1097" y="304.4575">Check if album already persisted</text><g class="message" data-entity-1="part6" data-entity-2="part4" id="msg8"><polygon fill="#181818" points="742.2007,334.6563,732.2007,338.6563,742.2007,342.6563,738.2007,338.6563" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="736.2007" x2="1085.396" y1="338.6563" y2="338.6563"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="62.6831" x="877.4568" y="333.5903">not found</text></g><g class="message" data-entity-1="part4" data-entity-2="part6" id="msg9"><polygon fill="#181818" points="1074.396,381.9219,1084.396,385.9219,1074.396,389.9219,1078.396,385.9219" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="731.2007" x2="1080.396" y1="385.9219" y2="385.9219"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="251.5132" x="783.0417" y="380.856">artists.Create(artist, state=monitored)</text></g><path d="M1091,351.6563 L1091,406.6563 L1242,406.6563 L1242,361.6563 L1232,351.6563 L1091,351.6563" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M1232,351.6563 L1232,361.6563 L1242,361.6563 L1232,351.6563" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="81.0024" x="1097" y="368.7231">Upsert artist</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="121.0688" x="1097" y="383.856">never downgrades</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="130.6855" x="1097" y="398.9888">monitored/excluded</text><g class="message" data-entity-1="part4" data-entity-2="part6" id="msg11"><polygon fill="#181818" points="1074.396,447.3203,1084.396,451.3203,1074.396,455.3203,1078.396,451.3203" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="731.2007" x2="1080.396" y1="451.3203" y2="451.3203"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="265.1987" x="776.199" y="446.2544">albums.Create(album, state=monitored)</text></g><path d="M1091,417.0547 L1091,472.0547 L1242,472.0547 L1242,427.0547 L1232,417.0547 L1091,417.0547" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M1232,417.0547 L1232,427.0547 L1242,427.0547 L1232,417.0547" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="87.8452" x="1097" y="434.1216">Upsert album</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="121.0688" x="1097" y="449.2544">never downgrades</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="130.6855" x="1097" y="464.3872">monitored/excluded</text><g class="message" data-entity-1="part4" data-entity-2="part3" id="msg13"><polygon fill="#181818" points="509.105,494.5859,499.105,498.5859,509.105,502.5859,505.105,498.5859" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="503.105" x2="730.2007" y1="498.5859" y2="498.5859"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="41.6597" x="593.823" y="493.52">Album</text></g><rect fill="#EEEEEE" height="3" style="stroke:#EEEEEE;stroke-width:1;" width="2328.1533" x="0" y="527.1523"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="527.1523" y2="527.1523"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="530.1523" y2="530.1523"/><rect fill="#EEEEEE" height="23.1328" style="stroke:#000000;stroke-width:2;" width="166.9976" x="1080.5779" y="516.5859"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="148.4717" x="1086.5779" y="532.6528">2. Set Monitor State</text><g class="message" data-entity-1="part3" data-entity-2="part6" id="msg14"><polygon fill="#181818" points="1074.396,566.8516,1084.396,570.8516,1074.396,574.8516,1078.396,570.8516" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1080.396" y1="570.8516" y2="570.8516"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="241.8838" x="671.3086" y="565.7856">albums.GetByExternalID(external_id)</text></g><g class="message" data-entity-1="part6" data-entity-2="part3" id="msg15"><polygon fill="#181818" points="509.105,595.9844,499.105,599.9844,509.105,603.9844,505.105,599.9844" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="503.105" x2="1085.396" y1="599.9844" y2="599.9844"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="58.1636" x="763.1687" y="594.9185">dbAlbum</text></g><g class="message" data-entity-1="part3" data-entity-2="part6" id="msg16"><polygon fill="#181818" points="1074.396,635.6836,1084.396,639.6836,1074.396,643.6836,1078.396,639.6836" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1080.396" y1="639.6836" y2="639.6836"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="254.1982" x="665.1514" y="634.6177">albums.SetMonitorState(id, monitored)</text></g><path d="M1091,612.9844 L1091,652.9844 L1242,652.9844 L1242,622.9844 L1232,612.9844 L1091,612.9844" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M1232,612.9844 L1232,622.9844 L1242,622.9844 L1232,612.9844" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="96.1797" x="1097" y="630.0513">Explicitly mark</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="130.8506" x="1097" y="645.1841">album as monitored</text><rect fill="#EEEEEE" height="3" style="stroke:#EEEEEE;stroke-width:1;" width="2328.1533" x="0" y="678.8164"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="678.8164" y2="678.8164"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="681.8164" y2="681.8164"/><rect fill="#EEEEEE" height="23.1328" style="stroke:#000000;stroke-width:2;" width="211.8057" x="1058.1738" y="668.25"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="193.2798" x="1064.1738" y="684.3169">3. Check If Already Owned</text><g class="message" data-entity-1="part3" data-entity-2="part6" id="msg18"><polygon fill="#181818" points="1074.396,718.5156,1084.396,722.5156,1074.396,726.5156,1078.396,722.5156" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1080.396" y1="722.5156" y2="722.5156"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="372.3091" x="606.0959" y="717.4497">downloads.HasAlbumInQuality(album_id, format, quality)</text></g><g class="message" data-entity-1="part6" data-entity-2="part3" id="msg19"><polygon fill="#181818" points="509.105,747.6484,499.105,751.6484,509.105,755.6484,505.105,751.6484" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="503.105" x2="1085.396" y1="751.6484" y2="751.6484"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="113.6992" x="735.4009" y="746.5825">false (not owned)</text></g><rect fill="#EEEEEE" height="3" style="stroke:#EEEEEE;stroke-width:1;" width="2328.1533" x="0" y="780.2148"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="780.2148" y2="780.2148"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="783.2148" y2="783.2148"/><rect fill="#EEEEEE" height="23.1328" style="stroke:#000000;stroke-width:2;" width="155.4512" x="1086.3511" y="769.6484"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="136.9253" x="1092.3511" y="785.7153">4. Search Indexers</text><g class="message" data-entity-1="part3" data-entity-2="part7" id="msg20"><polygon fill="#181818" points="1187.2212,819.9141,1197.2212,823.9141,1187.2212,827.9141,1191.2212,823.9141" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1193.2212" y1="823.9141" y2="823.9141"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="233.1113" x="732.1074" y="818.8481">Search(artist + album title, tracker)</text></g><g class="message" data-entity-1="part7" data-entity-2="part7" id="msg21"><line style="stroke:#181818;stroke-width:1;" x1="1199.2212" x2="1241.2212" y1="868.1797" y2="868.1797"/><line style="stroke:#181818;stroke-width:1;" x1="1241.2212" x2="1241.2212" y1="868.1797" y2="881.1797"/><line style="stroke:#181818;stroke-width:1;" x1="1200.2212" x2="1241.2212" y1="881.1797" y2="881.1797"/><polygon fill="#181818" points="1210.2212,877.1797,1200.2212,881.1797,1210.2212,885.1797,1206.2212,881.1797" style="stroke:#181818;stroke-width:1;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="69.3672" x="1264.0547" y="847.981">Jackett API</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="185.0342" x="1206.2212" y="863.1138">/api/v2.0/indexers/all/results</text></g><g class="message" data-entity-1="part7" data-entity-2="part3" id="msg22"><polygon fill="#181818" points="509.105,906.3125,499.105,910.3125,509.105,914.3125,505.105,910.3125" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="503.105" x2="1198.2212" y1="910.3125" y2="910.3125"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="172.2437" x="762.5413" y="905.2466">SearchResponse (N items)</text></g><rect fill="#EEEEEE" height="3" style="stroke:#EEEEEE;stroke-width:1;" width="2328.1533" x="0" y="938.8789"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="938.8789" y2="938.8789"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="941.8789" y2="941.8789"/><rect fill="#EEEEEE" height="23.1328" style="stroke:#000000;stroke-width:2;" width="225.6245" x="1051.2644" y="928.3125"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="207.0986" x="1057.2644" y="944.3794">5. Parse &amp; Resolve Releases</text><path d="M390.2632,968.4453 L466.8872,968.4453 L466.8872,975.5781 L456.8872,985.5781 L390.2632,985.5781 L390.2632,968.4453" fill="#EEEEEE" style="stroke:#000000;stroke-width:1.5;"/><rect fill="none" height="284" style="stroke:#000000;stroke-width:1.5;" width="1557.0654" x="390.2632" y="968.4453"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="31.624" x="405.2632" y="981.5122">loop</text><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="367.9038" x="481.8872" y="980.6558">[for each search result (with download link &amp; seeders &gt; 0)]</text><path d="M400.2632,992.5781 L464.7061,992.5781 L464.7061,999.7109 L454.7061,1009.7109 L400.2632,1009.7109 L400.2632,992.5781" fill="#EEEEEE" style="stroke:#000000;stroke-width:1.5;"/><rect fill="none" height="252.8672" style="stroke:#000000;stroke-width:1.5;" width="1200.7622" x="400.2632" y="992.5781"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="19.4429" x="415.2632" y="1005.645">alt</text><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="83.8804" x="479.7061" y="1004.7886">[magnet link]</text><path d="M1606.0254,997.5781 L1606.0254,1037.5781 L1932.0254,1037.5781 L1932.0254,1007.5781 L1922.0254,997.5781 L1606.0254,997.5781" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M1922.0254,997.5781 L1922.0254,1007.5781 L1932.0254,1007.5781 L1922.0254,997.5781" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="253.2524" x="1612.0254" y="1014.645">Extract: format, bitDepth, sampleRate,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="305.3032" x="1612.0254" y="1029.7778">source, trackCount, coverArt, cueSheet, ripLog</text><g class="message" data-entity-1="part3" data-entity-2="part8" id="msg23"><polygon fill="#181818" points="1386.2554,1044.9766,1396.2554,1048.9766,1386.2554,1052.9766,1390.2554,1048.9766" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1392.2554" y1="1048.9766" y2="1048.9766"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="135.1162" x="880.6221" y="1043.9106">Resolve(magnet_uri)</text></g><path d="M1403,1014.7109 L1403,1069.7109 L1585,1069.7109 L1585,1024.7109 L1575,1014.7109 L1403,1014.7109" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M1575,1014.7109 L1575,1024.7109 L1585,1024.7109 L1575,1014.7109" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="161.77" x="1409" y="1031.7778">DHT lookup, 30s timeout</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="141.4131" x="1409" y="1046.9106">15s early exit if peers</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="101.7974" x="1409" y="1062.0435">but none active</text><g class="message" data-entity-1="part8" data-entity-2="part3" id="msg25"><polygon fill="#181818" points="509.105,1092.2422,499.105,1096.2422,509.105,1100.2422,505.105,1096.2422" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="503.105" x2="1397.2554" y1="1096.2422" y2="1096.2422"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="226.0146" x="835.1729" y="1091.1763">torrent metadata (files, hash, size)</text></g><g class="message" data-entity-1="part3" data-entity-2="part3" id="msg26"><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="540.105" y1="1125.375" y2="1125.375"/><line style="stroke:#181818;stroke-width:1;" x1="540.105" x2="540.105" y1="1125.375" y2="1138.375"/><line style="stroke:#181818;stroke-width:1;" x1="499.105" x2="540.105" y1="1138.375" y2="1138.375"/><polygon fill="#181818" points="509.105,1134.375,499.105,1138.375,509.105,1142.375,505.105,1138.375" style="stroke:#181818;stroke-width:1;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="219.0957" x="505.105" y="1120.3091">ParseTorrent(torrentData, album)</text></g><line style="stroke:#000000;stroke-width:1;stroke-dasharray:2,2;" x1="400.2632" x2="1601.0254" y1="1147.375" y2="1147.375"/><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="116.8911" x="405.2632" y="1157.5854">[HTTP torrent link]</text><g class="message" data-entity-1="part3" data-entity-2="part3" id="msg27"><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="540.105" y1="1182.3125" y2="1182.3125"/><line style="stroke:#181818;stroke-width:1;" x1="540.105" x2="540.105" y1="1182.3125" y2="1195.3125"/><line style="stroke:#181818;stroke-width:1;" x1="499.105" x2="540.105" y1="1195.3125" y2="1195.3125"/><polygon fill="#181818" points="509.105,1191.3125,499.105,1195.3125,509.105,1199.3125,505.105,1195.3125" style="stroke:#181818;stroke-width:1;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="169.1587" x="505.105" y="1177.2466">downloadTorrentData(url)</text></g><g class="message" data-entity-1="part3" data-entity-2="part3" id="msg28"><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="540.105" y1="1224.4453" y2="1224.4453"/><line style="stroke:#181818;stroke-width:1;" x1="540.105" x2="540.105" y1="1224.4453" y2="1237.4453"/><line style="stroke:#181818;stroke-width:1;" x1="499.105" x2="540.105" y1="1237.4453" y2="1237.4453"/><polygon fill="#181818" points="509.105,1233.4453,499.105,1237.4453,509.105,1241.4453,505.105,1237.4453" style="stroke:#181818;stroke-width:1;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="219.0957" x="505.105" y="1219.3794">ParseTorrent(torrentData, album)</text></g><rect fill="#EEEEEE" height="3" style="stroke:#EEEEEE;stroke-width:1;" width="2328.1533" x="0" y="1280.0117"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="1280.0117" y2="1280.0117"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="1283.0117" y2="1283.0117"/><rect fill="#EEEEEE" height="23.1328" style="stroke:#000000;stroke-width:2;" width="179.2358" x="1074.4587" y="1269.4453"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="160.71" x="1080.4587" y="1285.5122">6. Filter &amp; Select Best</text><g class="message" data-entity-1="part3" data-entity-2="part3" id="msg29"><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="540.105" y1="1327.7773" y2="1327.7773"/><line style="stroke:#181818;stroke-width:1;" x1="540.105" x2="540.105" y1="1327.7773" y2="1340.7773"/><line style="stroke:#181818;stroke-width:1;" x1="499.105" x2="540.105" y1="1340.7773" y2="1340.7773"/><polygon fill="#181818" points="509.105,1336.7773,499.105,1340.7773,509.105,1344.7773,505.105,1340.7773" style="stroke:#181818;stroke-width:1;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="200.77" x="505.105" y="1322.7114">filterByQuality(parsed, quality)</text></g><path d="M717.77,1307.5781 L717.77,1347.5781 L984.77,1347.5781 L984.77,1317.5781 L974.77,1307.5781 L717.77,1307.5781" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M974.77,1307.5781 L974.77,1317.5781 L984.77,1317.5781 L974.77,1307.5781" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="246.4097" x="723.77" y="1324.645">Match LOSSLESS/LOSSY/UNSPECIFIED</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="147.4624" x="723.77" y="1339.7778">against release format</text><g class="message" data-entity-1="part3" data-entity-2="part3" id="msg31"><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="540.105" y1="1373.9766" y2="1373.9766"/><line style="stroke:#181818;stroke-width:1;" x1="540.105" x2="540.105" y1="1373.9766" y2="1386.9766"/><line style="stroke:#181818;stroke-width:1;" x1="499.105" x2="540.105" y1="1386.9766" y2="1386.9766"/><polygon fill="#181818" points="509.105,1382.9766,499.105,1386.9766,509.105,1390.9766,505.105,1386.9766" style="stroke:#181818;stroke-width:1;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="175.4238" x="505.105" y="1368.9106">selectBestRelease(filtered)</text></g><path d="M692.4238,1361.3438 L692.4238,1386.3438 L885.4238,1386.3438 L885.4238,1371.3438 L875.4238,1361.3438 L692.4238,1361.3438" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M875.4238,1361.3438 L875.4238,1371.3438 L885.4238,1371.3438 L875.4238,1361.3438" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="172.4404" x="698.4238" y="1378.4106">Highest seeder count wins</text><rect fill="#EEEEEE" height="3" style="stroke:#EEEEEE;stroke-width:1;" width="2328.1533" x="0" y="1415.543"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="1415.543" y2="1415.543"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="1418.543" y2="1418.543"/><rect fill="#EEEEEE" height="23.1328" style="stroke:#000000;stroke-width:2;" width="192.0771" x="1068.0381" y="1404.9766"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="173.5513" x="1074.0381" y="1421.0435">7. Add to Torrent Client</text><g class="message" data-entity-1="part3" data-entity-2="part9" id="msg33"><polygon fill="#181818" points="1512.9551,1455.2422,1522.9551,1459.2422,1512.9551,1463.2422,1516.9551,1459.2422" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1518.9551" y1="1459.2422" y2="1459.2422"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="68.9419" x="977.0591" y="1454.1763">Find(hash)</text></g><g class="message" data-entity-1="part9" data-entity-2="part3" id="msg34"><polygon fill="#181818" points="509.105,1484.375,499.105,1488.375,509.105,1492.375,505.105,1488.375" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="503.105" x2="1523.9551" y1="1488.375" y2="1488.375"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="62.6831" x="980.1885" y="1483.3091">not found</text></g><path d="M400.2632,1503.375 L464.7061,1503.375 L464.7061,1510.5078 L454.7061,1520.5078 L400.2632,1520.5078 L400.2632,1503.375" fill="#EEEEEE" style="stroke:#000000;stroke-width:1.5;"/><rect fill="none" height="90.2031" style="stroke:#000000;stroke-width:1.5;" width="1187.7593" x="400.2632" y="1503.375"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="19.4429" x="415.2632" y="1516.4419">alt</text><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="83.8804" x="479.7061" y="1515.5854">[magnet link]</text><g class="message" data-entity-1="part3" data-entity-2="part9" id="msg35"><polygon fill="#181818" points="1512.9551,1537.6406,1522.9551,1541.6406,1512.9551,1545.6406,1516.9551,1541.6406" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1518.9551" y1="1541.6406" y2="1541.6406"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="158.2217" x="932.4192" y="1536.5747">AddMagnet(magnet_uri)</text></g><line style="stroke:#000000;stroke-width:1;stroke-dasharray:2,2;" x1="400.2632" x2="1588.0225" y1="1550.6406" y2="1550.6406"/><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="77.8862" x="405.2632" y="1560.8511">[torrent file]</text><g class="message" data-entity-1="part3" data-entity-2="part9" id="msg36"><polygon fill="#181818" points="1512.9551,1581.5781,1522.9551,1585.5781,1512.9551,1589.5781,1516.9551,1585.5781" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1518.9551" y1="1585.5781" y2="1585.5781"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="103.2573" x="959.9014" y="1580.5122">AddTorrent(file)</text></g><g class="message" data-entity-1="part9" data-entity-2="part3" id="msg37"><polygon fill="#181818" points="509.105,1617.7109,499.105,1621.7109,509.105,1625.7109,505.105,1621.7109" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="503.105" x2="1523.9551" y1="1621.7109" y2="1621.7109"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="18.7573" x="1002.1514" y="1616.645">OK</text></g><rect fill="#EEEEEE" height="3" style="stroke:#EEEEEE;stroke-width:1;" width="2328.1533" x="0" y="1650.2773"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="1650.2773" y2="1650.2773"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="1653.2773" y2="1653.2773"/><rect fill="#EEEEEE" height="23.1328" style="stroke:#000000;stroke-width:2;" width="240.2114" x="1043.9709" y="1639.7109"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="221.6855" x="1049.9709" y="1655.7778">8. Persist Torrent &amp; Download</text><g class="message" data-entity-1="part3" data-entity-2="part6" id="msg38"><polygon fill="#181818" points="1074.396,1700.543,1084.396,1704.543,1074.396,1708.543,1078.396,1704.543" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1080.396" y1="1704.543" y2="1704.543"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="154.6797" x="714.9106" y="1699.4771">torrents.Create(torrent)</text></g><path d="M1091,1677.8438 L1091,1717.8438 L1260,1717.8438 L1260,1687.8438 L1250,1677.8438 L1091,1677.8438" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M1250,1677.8438 L1250,1687.8438 L1260,1687.8438 L1250,1677.8438" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="129.5366" x="1097" y="1694.9106">Upsert on info_hash</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="148.5923" x="1097" y="1710.0435">updates seeders/peers</text><g class="message" data-entity-1="part3" data-entity-2="part6" id="msg40"><polygon fill="#181818" points="1074.396,1740.2422,1084.396,1744.2422,1074.396,1748.2422,1078.396,1744.2422" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1080.396" y1="1744.2422" y2="1744.2422"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="194.4795" x="695.0107" y="1739.1763">torrents.GetByInfoHash(hash)</text></g><g class="message" data-entity-1="part6" data-entity-2="part3" id="msg41"><polygon fill="#181818" points="509.105,1769.375,499.105,1773.375,509.105,1777.375,505.105,1773.375" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="503.105" x2="1085.396" y1="1773.375" y2="1773.375"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="167.5146" x="708.4932" y="1768.3091">savedTorrent (with DB id)</text></g><g class="message" data-entity-1="part3" data-entity-2="part6" id="msg42"><polygon fill="#181818" points="1074.396,1798.5078,1084.396,1802.5078,1074.396,1806.5078,1078.396,1802.5078" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1080.396" y1="1802.5078" y2="1802.5078"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="289.3325" x="647.5842" y="1797.4419">downloads.GetActiveByTorrentID(torrent_id)</text></g><g class="message" data-entity-1="part6" data-entity-2="part3" id="msg43"><polygon fill="#181818" points="509.105,1827.6406,499.105,1831.6406,509.105,1835.6406,505.105,1831.6406" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="503.105" x2="1085.396" y1="1831.6406" y2="1831.6406"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="203.7915" x="690.3547" y="1826.5747">not found (no active download)</text></g><g class="message" data-entity-1="part3" data-entity-2="part6" id="msg44"><polygon fill="#181818" points="1074.396,1867.3398,1084.396,1871.3398,1074.396,1875.3398,1078.396,1871.3398" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1080.396" y1="1871.3398" y2="1871.3398"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="190.252" x="697.1245" y="1866.2739">downloads.Create(download)</text></g><path d="M1091,1844.6406 L1091,1884.6406 L1279,1884.6406 L1279,1854.6406 L1269,1844.6406 L1091,1844.6406" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M1269,1844.6406 L1269,1854.6406 L1279,1854.6406 L1269,1844.6406" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="147.0117" x="1097" y="1861.7075">state = "downloading"</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="167.5337" x="1097" y="1876.8403">format, quality, qbit_hash</text><g class="message" data-entity-1="part6" data-entity-2="part3" id="msg46"><polygon fill="#181818" points="509.105,1907.0391,499.105,1911.0391,509.105,1915.0391,505.105,1911.0391" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="503.105" x2="1085.396" y1="1911.0391" y2="1911.0391"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="143.7744" x="720.3633" y="1905.9731">download (with DB id)</text></g><rect fill="#EEEEEE" height="3" style="stroke:#EEEEEE;stroke-width:1;" width="2328.1533" x="0" y="1939.6055"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="1939.6055" y2="1939.6055"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="1942.6055" y2="1942.6055"/><rect fill="#EEEEEE" height="23.1328" style="stroke:#000000;stroke-width:2;" width="212.8848" x="1057.6343" y="1929.0391"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="194.3589" x="1063.6343" y="1945.106">9. Schedule Download Poll</text><g class="message" data-entity-1="part3" data-entity-2="part10" id="msg47"><polygon fill="#181818" points="1626.3794,1997.4375,1636.3794,2001.4375,1626.3794,2005.4375,1630.3794,2001.4375" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1632.3794" y1="2001.4375" y2="2001.4375"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="164.3281" x="986.0781" y="1996.3716">Insert(PollDownloadArgs)</text></g><path d="M1643,1967.1719 L1643,2022.1719 L1838,2022.1719 L1838,1977.1719 L1828,1967.1719 L1643,1967.1719" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M1828,1967.1719 L1828,1977.1719 L1838,1977.1719 L1828,1967.1719" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="172.2817" x="1649" y="1984.2388">download_id, torrent_hash</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="136.5952" x="1649" y="1999.3716">check_interval = 30s</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="174.5288" x="1649" y="2014.5044">scheduled_at = now + 30s</text><g class="message" data-entity-1="part10" data-entity-2="part3" id="msg49"><polygon fill="#181818" points="509.105,2044.7031,499.105,2048.7031,509.105,2052.7031,505.105,2048.7031" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="503.105" x2="1637.3794" y1="2048.7031" y2="2048.7031"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="90.4604" x="1023.012" y="2043.6372">job scheduled</text></g><rect fill="#EEEEEE" height="3" style="stroke:#EEEEEE;stroke-width:1;" width="2328.1533" x="0" y="2077.2695"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="2077.2695" y2="2077.2695"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="2080.2695" y2="2080.2695"/><rect fill="#EEEEEE" height="23.1328" style="stroke:#000000;stroke-width:2;" width="228.9507" x="1049.6013" y="2066.7031"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="210.4248" x="1055.6013" y="2082.77">10. Build &amp; Return Response</text><g class="message" data-entity-1="part3" data-entity-2="part6" id="msg50"><polygon fill="#181818" points="1074.396,2116.9688,1084.396,2120.9688,1074.396,2124.9688,1078.396,2120.9688" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1080.396" y1="2120.9688" y2="2120.9688"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="241.8838" x="671.3086" y="2115.9028">albums.GetByExternalID(external_id)</text></g><g class="message" data-entity-1="part6" data-entity-2="part3" id="msg51"><polygon fill="#181818" points="509.105,2146.1016,499.105,2150.1016,509.105,2154.1016,505.105,2150.1016" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="503.105" x2="1085.396" y1="2150.1016" y2="2150.1016"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="134.9639" x="724.7686" y="2145.0356">dbAlbum (refreshed)</text></g><g class="message" data-entity-1="part3" data-entity-2="part6" id="msg52"><polygon fill="#181818" points="1074.396,2175.2344,1084.396,2179.2344,1074.396,2183.2344,1078.396,2179.2344" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1080.396" y1="2179.2344" y2="2179.2344"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="238.291" x="673.105" y="2174.1685">downloads.GetByAlbumID(album_id)</text></g><g class="message" data-entity-1="part6" data-entity-2="part3" id="msg53"><polygon fill="#181818" points="509.105,2204.3672,499.105,2208.3672,509.105,2212.3672,505.105,2208.3672" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="503.105" x2="1085.396" y1="2208.3672" y2="2208.3672"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="148.5542" x="717.9734" y="2203.3013">downloads (with state)</text></g><g class="message" data-entity-1="part3" data-entity-2="part6" id="msg54"><polygon fill="#181818" points="1074.396,2233.5,1084.396,2237.5,1074.396,2241.5,1078.396,2237.5" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="498.105" x2="1080.396" y1="2237.5" y2="2237.5"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="275.4312" x="654.5349" y="2232.4341">artists.GetByExternalID(artist_external_id)</text></g><g class="message" data-entity-1="part6" data-entity-2="part3" id="msg55"><polygon fill="#181818" points="509.105,2262.6328,499.105,2266.6328,509.105,2270.6328,505.105,2266.6328" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="503.105" x2="1085.396" y1="2266.6328" y2="2266.6328"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="51.3208" x="766.5901" y="2261.5669">dbArtist</text></g><g class="message" data-entity-1="part3" data-entity-2="part2" id="msg56"><polygon fill="#181818" points="331.0093,2317.4648,321.0093,2321.4648,331.0093,2325.4648,327.0093,2321.4648" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="325.0093" x2="497.105" y1="2321.4648" y2="2321.4648"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="154.0957" x="332.0093" y="2316.3989">MonitorAlbumResponse</text></g><path d="M503,2279.6328 L503,2349.6328 L799,2349.6328 L799,2289.6328 L789,2279.6328 L503,2279.6328" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M789,2279.6328 L789,2289.6328 L799,2289.6328 L789,2279.6328" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="275.4883" x="509" y="2296.6997">album: id, title, monitor_state=monitored,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="208.9077" x="517.2646" y="2311.8325">download: state, format, quality</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="197.958" x="509" y="2326.9653">artist: id, name, monitor_state</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="246.8096" x="509" y="2342.0981">release: hash, format, seeders, tracks</text><g class="message" data-entity-1="part2" data-entity-2="part1" id="msg58"><polygon fill="#181818" points="39.2651,2372.2969,29.2651,2376.2969,39.2651,2380.2969,35.2651,2376.2969" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="33.2651" x2="319.0093" y1="2376.2969" y2="2376.2969"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="154.0957" x="97.0894" y="2371.231">MonitorAlbumResponse</text></g><rect fill="#EEEEEE" height="3" style="stroke:#EEEEEE;stroke-width:1;" width="2328.1533" x="0" y="2404.8633"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="2404.8633" y2="2404.8633"/><line style="stroke:#000000;stroke-width:1;" x1="0" x2="2328.1533" y1="2407.8633" y2="2407.8633"/><rect fill="#EEEEEE" height="23.1328" style="stroke:#000000;stroke-width:2;" width="339.0635" x="994.5449" y="2394.2969"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="320.5376" x="1000.5449" y="2410.3638">11. Async: Download Polling (River Worker)</text><g class="message" data-entity-1="part10" data-entity-2="part11" id="msg59"><polygon fill="#181818" points="1814.7075,2444.5625,1824.7075,2448.5625,1814.7075,2452.5625,1818.7075,2448.5625" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="1638.3794" x2="1820.7075" y1="2448.5625" y2="2448.5625"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="160.7227" x="1652.1821" y="2443.4966">Work(PollDownloadArgs)</text></g><g class="message" data-entity-1="part11" data-entity-2="part9" id="msg60"><polygon fill="#181818" points="1535.9551,2473.6953,1525.9551,2477.6953,1535.9551,2481.6953,1531.9551,2477.6953" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="1529.9551" x2="1825.7075" y1="2477.6953" y2="2477.6953"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="68.9419" x="1641.3604" y="2472.6294">Find(hash)</text></g><g class="message" data-entity-1="part9" data-entity-2="part11" id="msg61"><polygon fill="#181818" points="1814.7075,2502.8281,1824.7075,2506.8281,1814.7075,2510.8281,1818.7075,2506.8281" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;stroke-dasharray:2,2;" x1="1524.9551" x2="1820.7075" y1="2506.8281" y2="2506.8281"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="222.5044" x="1564.5791" y="2501.7622">TorrentInfo (progress, state, path)</text></g><path d="M1033.0195,2521.8281 L1097.4624,2521.8281 L1097.4624,2528.9609 L1087.4624,2538.9609 L1033.0195,2538.9609 L1033.0195,2521.8281" fill="#EEEEEE" style="stroke:#000000;stroke-width:1.5;"/><rect fill="none" height="211.8672" style="stroke:#000000;stroke-width:1.5;" width="1285.1338" x="1033.0195" y="2521.8281"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="19.4429" x="1048.0195" y="2534.895">alt</text><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="115.6235" x="1112.4624" y="2534.0386">[progress &lt; 100%]</text><g class="message" data-entity-1="part11" data-entity-2="part10" id="msg62"><polygon fill="#181818" points="1649.3794,2559.0938,1639.3794,2563.0938,1649.3794,2567.0938,1645.3794,2563.0938" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="1643.3794" x2="1825.7075" y1="2563.0938" y2="2563.0938"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="164.3281" x="1650.3794" y="2558.0278">Insert(PollDownloadArgs)</text></g><path d="M1831,2543.9609 L1831,2568.9609 L2060,2568.9609 L2060,2553.9609 L2050,2543.9609 L1831,2543.9609" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M2050,2543.9609 L2050,2553.9609 L2060,2553.9609 L2050,2543.9609" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="208.6602" x="1837" y="2561.0278">Reschedule after check_interval</text><line style="stroke:#000000;stroke-width:1;stroke-dasharray:2,2;" x1="1033.0195" x2="2318.1533" y1="2575.0938" y2="2575.0938"/><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="124.8403" x="1038.0195" y="2585.3042">[progress == 100%]</text><g class="message" data-entity-1="part11" data-entity-2="part6" id="msg64"><polygon fill="#181818" points="1097.396,2606.0313,1087.396,2610.0313,1097.396,2614.0313,1093.396,2610.0313" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="1091.396" x2="1825.7075" y1="2610.0313" y2="2610.0313"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="262.7739" x="1325.1648" y="2604.9653">downloads.SetCompleted(id, save_path)</text></g><g class="message" data-entity-1="part11" data-entity-2="part11" id="msg65"><line style="stroke:#181818;stroke-width:1;" x1="1826.7075" x2="1868.7075" y1="2650.7969" y2="2650.7969"/><line style="stroke:#181818;stroke-width:1;" x1="1868.7075" x2="1868.7075" y1="2650.7969" y2="2663.7969"/><line style="stroke:#181818;stroke-width:1;" x1="1827.7075" x2="1868.7075" y1="2663.7969" y2="2663.7969"/><polygon fill="#181818" points="1837.7075,2659.7969,1827.7075,2663.7969,1837.7075,2667.7969,1833.7075,2663.7969" style="stroke:#181818;stroke-width:1;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="213.7065" x="1833.7075" y="2645.731">scanAndHashFiles(content_path)</text></g><path d="M2058.7065,2623.0313 L2058.7065,2678.0313 L2301.7065,2678.0313 L2301.7065,2633.0313 L2291.7065,2623.0313 L2058.7065,2623.0313" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M2291.7065,2623.0313 L2291.7065,2633.0313 L2301.7065,2633.0313 L2291.7065,2623.0313" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="222.7393" x="2064.7065" y="2640.0981">Walk directory, identify audio files</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="135.3003" x="2064.7065" y="2655.231">(.flac, .mp3, .aac, ...)</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="151.1885" x="2064.7065" y="2670.3638">SHA-256 hash each file</text><g class="message" data-entity-1="part11" data-entity-2="part6" id="msg67"><polygon fill="#181818" points="1097.396,2711.1289,1087.396,2715.1289,1097.396,2719.1289,1093.396,2715.1289" style="stroke:#181818;stroke-width:1;"/><line style="stroke:#181818;stroke-width:1;" x1="1091.396" x2="1825.7075" y1="2715.1289" y2="2715.1289"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="217.6294" x="1347.7371" y="2710.063">download_files.CreateBatch(files)</text></g><path d="M1831,2688.4297 L1831,2728.4297 L2035,2728.4297 L2035,2698.4297 L2025,2688.4297 L1831,2688.4297" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M2025,2688.4297 L2025,2698.4297 L2035,2698.4297 L2025,2688.4297" fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="183.3584" x="1837" y="2705.4966">file_path, file_size, file_type,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="162.4238" x="1837" y="2720.6294">sha256_hash, verified_at</text><?plantuml-src hLXjRzis4FwkNt48i4B673jjrsupbW9sd3RUaZQ9KnG331YCTBQvo9H2KacyNx_ZcomfTji1zGT7ek_zddjXr1qN1PDi3GhlInG9Ng1IR8d3Z2y592WqoaXLL19LaGiLg4QOvOz3AVD7qBB4A6A9pYMSP9mO8sBHFE454neEbjUN9p15-O3o09ZoZqsQYrBnPBYKk6Ganb3m12jgUcwHesOfqwnE6CuYytNB5CB1sXyTiY1v9c9ZJgVY-41lDOxBN6cYdLwTMuhngAbt8b9ymc0V2VkJ9NUejPFdVssPofO2zJMgF0i1S4TDifjSIegSYny9lXznhTsP4tv51qsMQqu2uQh4qWN0lZT9BlCi6-UF8ijP-YMNTzu0S-nUe-Zu65xsu3tgP0N3xBPSLu64u-CeSWR1uJkVjW5Sv8AJPPOsPkPxpjCkt9SiuthJ9JYOcCXEv1W2AyMhnPlefox1whuJHPx0q0Rj0_Y0kgca4rMcUKAJlHfX8377SDWGvboBDTSPTi74I6dLXIKA0dONUhqUcL4NFnuDm2fMFP8_sfm-KJq8bat6CVf7QvB8DOBaovKUmCaAaplW2yT8tn9Pke42fI9rc4RZKSiiueP5NefqXt9dO--4X6YCtMiNbAQtuxKB9BOC-5mebDgppeH0au2K0B2KB4Kr4nLV7v-Ih4p9fZrE1xNcxJkr6jB_hRGE3via2ybNFJhL0IymDUej7cj8-TuC-Q1NMj9RfsUtA5BhjLgbiS7s7hzFdugCIard6rWpUJSJFkrgos2TUTtpo9Wio4M7YK-F0jDT7gM-N5NlZ2bhw4HSkTggLTiYbskcgwfxxkI2PTJFOeEltAZgM4j-CM5baahTzohLDi6V3poTXntyx27jwwUgSK_UuFGz4OQNavdeiuBt7rxrZlhSQ-opBEjJqPMPLbl-kkrEzRKVE11_1AvnhPmBRtfmoIGTlm3VLEblXjIzdIzPdXScF82Ct5JEMwSEuaUkLrM48UFYZiGenDH4uXqSTIAW3oFIjUtHbiIUcK-zIzcV1y64s97FIyax5NaTAkEp6o3BxigY2w-F5CLnZNb99VhoZI9B9K48dxWslQD0CcOcRajD4WG23LPgx9LKfxaPC3ye8CmxY1SyCsrjnTIAYfV_YvrTNbG2R4Jz28gzj349whgqEsOqY3gxkRcizEsBphRKVAXljYBZKcO_mXXgcUqWKmCWND93g8vRhiTOQ1C2jYuolAQ2xiw4oakP11IVKFSbqYIdhZMKvgd4wGgHdYGlplDbP5GPvBsbCSapQYo4cIb1Bj4mGggDLWLjIz0IZpQXUWlZLrghsRhj5ymCuFDFq-dvwNJQDmz_zpz_d5wUdapUJqx7r5oMZ0jI9ntQlPCxDIjhdJ7EbqRiR6ati3FwOpnm5K0ne5308scn_lxQWs6QKhB19yDlTss7pMOoeD28D3PuwqJce0dGsfZRLLpFX95UX_D6OLa01kmPXEzb3kWnH1sRmESsVVhBUlaRzHCtdoitNq3OcNOrQ6z0DI73bhPh9EO2k5ZaSnENcIWBAavgKxxXz6sbxnLlPzg4k6aEh7nasrrUiGSCplhkHYHcwEqVAsPRiYrbjF6SD32zrftpiagU6IU-7LNolgR91sXBMe-GSYCT3iBFN2mFPg8rsEY1YjZ6x_aS3qbgEauv_Pt6NBB2jCnmcqgpzBRpQLVc0OqkawsulYqFvL8r3GxgxFmDyNA9JSnqdtDpOtfWfCIqU6epteHqpgXcA8oFD4RfbyWjxWrV_ibleQ9tI_bH3qObpr8xw7Gf1LGJySSkGX1BND24N9dsy3NOZ3Pk7ndNDl9zIL4-ApRDpyI6tRPjhZkVVyjgIrKBmPxRIOXN8utMz07O9BfbnYzhyzQEIuC2AdSyNfyjNjIMhJ5Ee63hjhoPyFrwu8Tn4E2RW9z2ghejaI-kpUxnnMA3Rcn3jH79e0blAY687RhSzQvZeUBnzgvsxnjOWXs8tv9ylRNNHOKsGiKBSI5pka0hrGqHAvWcHjltms_m1y7xw2VRlfiAlrMGxP5FOGc5pXPcD3TBqOsCIgqjgvrwcrYdEy19RXO6khFP2u3fitFdo7FUUYXKmiHGfAPblpShM9paP0erYYrptVmlBBk3b4iq_poXPiTJekMB3R0ovRcTSTH8ujuYOmbTKjV5Q_fczfakh3CnFHiUldhpraBBBRpLMDpltzoAzTrvPFOEjou-DyySMykxxj4ialvHRmgxIgqOwPyxQ5Fg-8BRVcTdxdy0?></g></svg>