@startuml Release Parsing Decision Tree skinparam ActivityBackgroundColor #f8f8f8 skinparam ActivityBorderColor #333333 skinparam DiamondBackgroundColor #fffde7 skinparam NoteBackgroundColor #e3f2fd title Release Parsing Decision Tree start partition "1. Resolve Torrent Data" { if (DownloadLink starts\nwith "magnet:?") then (yes) :MagnetResolver.Resolve(magnetURI); note right DHT lookup via anacrolix/torrent 30s timeout, 15s early exit if peers but none active end note if (Resolve succeeded?) then (yes) :torrentData = resolved bytes; else (no) :fallback to **title-only parse**; note right parser.Parse(item.Title) No torrent data available No info_hash computed end note goto TitleOnlyParse endif else (HTTP link) :downloadTorrentData(url); note right HTTP GET with 30s timeout Expects .torrent file bytes end note if (Download succeeded?) then (yes) :torrentData = downloaded bytes; else (no) :fallback to **title-only parse**; goto TitleOnlyParse endif endif } partition "2. ParseTorrent (torrentData + metadata album)" { partition "2a. Fill from Metadata Album" { :Artist = album.Artists[0].Name; :Album = album.Title; :Year = album.ReleaseDate[:4]; :Type = album.AlbumType (album/ep/single/compilation/...); :Genres = album.Genres[].Name; :Label = album.Label.Name; :TrackCount = album.TotalTracks; :ReleaseCount = album.TotalDiscs; } partition "2b. Fill from Torrent Data" { :metainfo.Load(torrentData); note right Bencode decode via anacrolix/torrent/metainfo end note if (Parse failed?) then (yes) :Append to ParseErrors; :Skip torrent analysis; else (no) :info = mi.UnmarshalInfo(); if (Unmarshal failed?) then (yes) :Append to ParseErrors; :Skip torrent analysis; else (no) :RawTitle = info.Name; :InfoHash = SHA1(info dict); if (info.Files is empty?\n(single-file torrent)) then (yes) :ext = filepath.Ext(info.Name); if (ext is audio?\n(.flac/.mp3/.aac/...)) then (yes) :Format = audioExtensions[ext]; :AudioFileCount = 1; :TotalAudioSize = info.Length; else (no) :Format = unknown; endif else (multi-file torrent) :Iterate all files in torrent; repeat :file = next torrent file; :ext = filepath.Ext(file.Path); if (ext is audio?) then (yes) :formatCounts[ext]++; :formatSizes[ext] += file.Length; :TrackNames += cleanTrackName(file); note right Strip leading "01. " or "1 - " from filename end note elseif (ext is .jpg/.jpeg/.png?) then (yes) :HasCoverArt = true; elseif (ext is .cue?) then (yes) :HasCueSheet = true; elseif (ext is .log?) then (yes) :HasRipLog = true; endif repeat while (more files?) :Format = dominant format\n(most audio files); :AudioFileCount = count of dominant; :TotalAudioSize = sum of dominant; endif if (HasRipLog?) then (yes) :Source = CD; note right .log file = EAC/XLD rip log implies CD source end note endif if (TrackCount == 0?) then (yes) :TrackCount = AudioFileCount; endif endif endif } partition "2c. Fill from Title (torrent name)" #f0f0f0 { label TitleParsing :title = info.Name (or item.Title for fallback); if (title matches\n"(\\d{2,3})\\s*kbps"?) then (yes) :Bitrate = matched value + " kbps"; endif :Try hi-res patterns (in order):; note right 1. "24Bit-96kHz" / "24 Bit / 48 kHz" 2. "FLAC 24-96" / "Flac 24-44" 3. "24Bit" (bit depth only) First match wins. end note if (Hi-res pattern matched?) then (yes) if (BitDepth still 0?) then (yes) :BitDepth = matched group 1; endif if (SampleRate still 0\nand group 2 exists?) then (yes) :SampleRate = matched × 1000; endif endif if (title matches\n"\\[(CD|WEB|Vinyl|...)\\]"\nand Source still unknown?) then (yes) :Source = matched value; note right CD, WEB, Vinyl/LP, Cassette/MC, DVD, Blu-Ray end note endif if (title matches\nrip type pattern?) then (yes) :RipType = matched value; note right vinyl rip, SACD-R, HDCD, DSD, tape rip end note endif } :ParsedSuccessfully = (Artist != "" && Album != ""); if (not ParsedSuccessfully?) then (yes) :ParseErrors += "missing artist or album"; endif :Return Release; stop } partition "3. Title-Only Parse (fallback)" #fff3e0 { label TitleOnlyParse :r = Release{RawTitle: item.Title}; note right No torrent data available. No InfoHash. No file analysis. No TrackNames. No cover/cue/log. Format stays **unknown**. end note goto TitleParsing } @enduml