194 lines
5.1 KiB
Plaintext
194 lines
5.1 KiB
Plaintext
@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
|