Struct Catalog

Source
pub struct Catalog {
Show 18 fields pub roots: Vec<String>, pub excluded: Vec<String>, pub scanned_at: u64, pub files: Vec<AudioFile>, pub file_mtime_subseconds: BTreeMap<String, u32>, pub file_added_at: BTreeMap<String, u64>, pub analyses: Vec<FileAnalysis>, pub artists: Vec<Artist>, pub releases: Vec<Release>, pub release_groups: Vec<ReleaseGroup>, pub tracks: Vec<Track>, pub recordings: Vec<Recording>, pub works: Vec<Work>, pub labels: Vec<Label>, pub genres: Vec<Genre>, pub credits: Vec<Credit>, pub relations: Vec<Relation>, pub genre_links: Vec<GenreLink>,
}
Expand description

The complete catalog.

Fields§

§roots: Vec<String>

Scanned root folders.

§excluded: Vec<String>

Folders never read, however deep under a root they sit.

Kept beside the roots rather than passed to each scan, because a plain aede scan re-reads every root: an exclusion that had to be retyped would be forgotten precisely when it mattered. Canonical, like the roots, so the comparison against a walked path is the same string comparison everywhere else in the program makes.

§scanned_at: u64

Date of the last scan (Unix epoch, seconds).

§files: Vec<AudioFile>

The files that were read, in the order the scan settled on.

§file_mtime_subseconds: BTreeMap<String, u32>

Nanosecond fractions of file modification dates, keyed by native path.

Stored as an optional mtime_subseconds field on each file row. Legacy rows without that field need one fresh read before they can be reused; guessing zero would miss real same-second changes. Keeping the fraction apart from epoch seconds avoids losing precision in JSON numbers.

§file_added_at: BTreeMap<String, u64>

First successful catalog observation by path, in Unix seconds. Absent legacy dates remain unknown; file modification dates are not substitutes.

§analyses: Vec<FileAnalysis>

Deep analyses imported from another tool, one row per path and source.

Optional by nature: a catalog without a single one works exactly the same. They are kept apart from the files rather than merged into them, so that a measurement always answers “who says so”.

Keyed by path, which means some of them may describe files the catalog does not hold — a library analysed before it was ever scanned. Those wait here until a scan brings the file in.

§artists: Vec<Artist>

Artists, one entry per normalized key.

§releases: Vec<Release>

Releases, one entry per title, owner and folder.

§release_groups: Vec<ReleaseGroup>

Release groups shared by explicitly identified local editions.

§tracks: Vec<Track>

Tracks, one entry per file that carried readable tags.

§recordings: Vec<Recording>

Recorded performances, distinct from their local track placements.

§works: Vec<Work>

Musical compositions explicitly linked to local recordings.

§labels: Vec<Label>

Labels, one entry per normalized key.

§genres: Vec<Genre>

Genres, one entry per normalized key.

§credits: Vec<Credit>

Every “who did what, on what” observation, without repeats.

§relations: Vec<Relation>

Links between entities; symmetric ones are stored in both directions.

§genre_links: Vec<GenreLink>

Attachments of genres to tracks and to releases.

Implementations§

Source§

impl Catalog

Source

pub fn composers_by_release(&self) -> BTreeMap<Id, BTreeSet<Id>>

Index credited composers once per projection/evaluation. Recording and work credits reach every local edition containing that recording; duplicate credits stay one identity. This reads the local graph only, never unaccepted external claims or audio files.

Source§

impl Catalog

Source

pub fn release_added_at(&self, id: Id) -> Option<u64>

Earliest known file entry date; any unknown placement keeps an existing edition undated.

Source

pub fn playback_release_order(&self, ids: Vec<Id>) -> Vec<Id> ⓘ

Order selected releases for playback: oldest first, unknown dates last. Equal years retain the CLI folder/title tie breakers; track order is untouched.

Source

pub fn artist(&self, id: Id) -> Option<&Artist>

The artist an id designates, or None when the id is out of range.

Source

pub fn release(&self, id: Id) -> Option<&Release>

The release an id designates, or None when the id is out of range.

Source

pub fn release_group(&self, id: Id) -> Option<&ReleaseGroup>

The canonical group an id designates, if this catalog identified it.

Source

pub fn track(&self, id: Id) -> Option<&Track>

The track an id designates, or None when the id is out of range.

Source

pub fn recording(&self, id: Id) -> Option<&Recording>

The recorded performance an id designates, if it is in this catalog.

Source

pub fn tracks_of_recording(&self, recording_id: Id) -> Vec<Id> ⓘ

Every local placement of one recording, in catalog order.

Source

pub fn work(&self, id: Id) -> Option<&Work>

The composition an id designates, if this catalog explicitly knows it.

Source

pub fn recordings_of_work(&self, work_id: Id) -> Vec<Id> ⓘ

Every recording explicitly known to realize this composition.

Source

pub fn find_recordings(&self, query: &str) -> Vec<&Recording>

Recordings whose title or MusicBrainz identifier matches the query.

Source

pub fn find_works(&self, query: &str) -> Vec<&Work>

Works whose title or MusicBrainz identifier matches the query.

Source

pub fn find_release_groups(&self, query: &str) -> Vec<&ReleaseGroup>

Release groups whose title or MusicBrainz identifier matches.

Source

pub fn file(&self, id: Id) -> Option<&AudioFile>

The file an id designates, or None when the id is out of range.

Source

pub fn relations_from(&self, kind: EntityKind, id: Id) -> Vec<&Relation>

Every outgoing graph relationship from one entity.

Source

pub fn related_entities( &self, kind: EntityKind, id: Id, relation_kind: &str, target_kind: EntityKind, ) -> Vec<Id> ⓘ

Targets reached through one typed relationship.

Source

pub fn analyses_of( &self, file: &AudioFile, ) -> impl Iterator<Item = &FileAnalysis>

Every imported analysis that describes this file, whatever the source.

Source

pub fn pending_analyses_list(&self) -> Vec<&FileAnalysis>

Imported analyses describing files the catalog does not hold, in full.

Same population Catalog::pending_analyses counts. Kept apart because most callers only want the number — doctor says “N waiting” on every run — and building the list, with its own reference into every path, is a heavier answer nobody should pay for just to learn how many there are. aede import --pending is the caller that does want the list, to say which ones.

Source

pub fn pending_analyses(&self) -> usize

Imported analyses describing files the catalog does not hold.

Not an error and not garbage: the usual reason is that the folder they speak of has not been scanned yet. Counting them is how the interface can say “twelve analyses are waiting for a scan” instead of losing them without a word.

Source

pub fn label(&self, id: Id) -> Option<&Label>

The label an id designates, or None when the id is out of range.

Source

pub fn genre(&self, id: Id) -> Option<&Genre>

The genre an id designates, or None when the id is out of range.

Source

pub fn total_duration_ms(&self) -> u64

Total duration of the library, saturating at u64::MAX for oversized measures.

Source

pub fn total_size(&self) -> u64

Total size on disk, saturating at u64::MAX for oversized measures.

Source

pub fn releases_as_album_artist(&self, artist_id: Id) -> Vec<Id> ⓘ

The artist’s own discography: releases they are the album artist of.

This is what a listener means by “their albums”. A guest appearance on somebody else’s record belongs in Catalog::guest_appearances.

Source

pub fn guest_appearances(&self, artist_id: Id) -> Vec<Id> ⓘ

Releases the artist is audible on without being the album artist: featured vocals, a guest solo, one track on a compilation.

Source

pub fn releases_with_writing_credit(&self, artist_id: Id) -> Vec<Id> ⓘ

Releases where the artist holds a credit that is not a performance.

All of them, including the ones they also play on. Ozzy Osbourne composes most of what he sings: a figure that subtracted those would report one album where the credits count sixty-nine, and the number would be right about a set nobody asked for.

Source

pub fn writing_tracks_of_artist(&self, artist_id: Id) -> Vec<Id> ⓘ

Tracks where the artist holds a credit that is not a performance.

Source

pub fn releases_written_without_performing(&self, artist_id: Id) -> Vec<Id> ⓘ

Releases the artist wrote or produced and is not audible on.

Not a measure of anything — a display set. It exists so the artist page can show the records that would otherwise never appear on it, without repeating the discography above. Never label it “writing”: that is Catalog::releases_with_writing_credit.

Source

pub fn performed_tracks_of_artist(&self, artist_id: Id) -> Vec<Id> ⓘ

Tracks the artist is audible on, without duplicates.

Source

pub fn written_tracks_without_performing(&self, artist_id: Id) -> Vec<Id> ⓘ

Tracks the artist wrote or produced and is not audible on.

The display counterpart of Catalog::performed_tracks_of_artist: together they cover every track credit without counting one twice, a track where someone both plays and composes going to the first. For “how much did this person write”, use Catalog::writing_tracks_of_artist.

Source

pub fn releases_of_artist(&self, artist_id: Id) -> Vec<Id> ⓘ

Every release the artist appears on, whatever their role.

Source

pub fn tracks_of_artist(&self, artist_id: Id) -> Vec<Id> ⓘ

Tracks credited to an artist, without duplicates.

A single artist may hold several roles on one track (performer and composer): without deduplication, every count would be inflated.

Source

pub fn credits_on(&self, kind: EntityKind, id: Id) -> Vec<(&Artist, &str)>

Artists credited on an entity, along with their role.

Source

pub fn neighbours_of_artist(&self, artist_id: Id) -> Vec<(&Artist, u32, &str)>

An artist’s neighbours in the graph, from strongest link to weakest.

Source

pub fn tracks_in_common(&self, a: Id, b: Id) -> Vec<Id> ⓘ

Tracks on which two artists are both credited in a performing role.

This is what the weight of a collaborated relation counts, recomputed on demand rather than stored: the credit table already holds the answer, and a second copy is a second thing that can fall out of step.

Source

pub fn related_releases(&self, release_id: Id, kind: &str) -> Vec<Id> ⓘ

Releases tied to this one by a relation of the given kind.

Used with crate::model::DUPLICATE and crate::model::OTHER_EDITION to answer “is this album here twice, and on purpose?”.

Source

pub fn genres_of(&self, kind: EntityKind, id: Id) -> Vec<&Genre>

Genres attached to an entity.

Source

pub fn search(&self, query: &str, limit: usize) -> Vec<SearchHit>

Case- and accent-insensitive search, across every entity.

Source

pub fn find_artist(&self, name: &str) -> Option<&Artist>

Finds an artist by name, up to normalization.

Source

pub fn find_artists(&self, name: &str) -> (Vec<&Artist>, TitleMatch)

Every artist whose name matches, exactly or failing that partially.

The rule Catalog::find_releases and Catalog::find_tracks already followed, and that this one did not. find_artist matched exactly and nothing else, so every caller that wanted osbourne to reach Ozzy bolted a fuzzy search underneath and took its first hit — an arbitrary answer among several, given without a word. On a shelf holding both Ozzy Osbourne and O. Osbourne that is not a nicety: aede artist osbourne and aede artist ozzy answered about two different people, one of them with a biography and thirteen albums and the other with seven.

So: exact first, and only widen when nothing was exact — the same shape, returning the same TitleMatch, so a caller can say which of the two happened and refuse to arbitrate between several.

Source

pub fn find_releases(&self, title: &str) -> (Vec<&Release>, TitleMatch)

One release by MusicBrainz identity, or every title match.

Same rule as Catalog::find_tracks, and for the same reason: a command must not pick one answer out of several without saying so. An identifier wins before names. Unlike tracks, two matching albums are two different editions — a shared prefix is not an ambiguity — which is why an exact title usually ends the name search without choosing one.

Source

pub fn find_tracks(&self, title: &str) -> (Vec<&Track>, TitleMatch)

Every track carrying this title, up to normalization.

A title is not an identifier: the same one legitimately comes back on the album, on a single and on a live record, and those are different recordings. All of them are returned, in catalog order.

Exact matches win. Only when there is none does the search widen to the titles containing the text, so that a half-remembered title still leads somewhere; TitleMatch says which of the two happened.

Source

pub fn find_genres(&self, name: &str) -> (Vec<&Genre>, TitleMatch)

Every genre whose name matches, exactly or failing that partially.

Same rule as Catalog::find_releases: “metal” must reach the genre spelled exactly that way without hiding “Black Metal” and “Doom Metal” when there is no exact one.

Source

pub fn find_labels(&self, name: &str) -> (Vec<&Label>, TitleMatch)

Every label whose name matches, exactly or failing that partially.

Source

pub fn tracks_of_genre(&self, genre_id: Id) -> Vec<Id> ⓘ

Tracks carrying a genre, directly or through their release.

A genre attached to an album is a genre of every track on it: tags put it in either place, and a listener does not think of the difference.

Source

pub fn releases_of_genre(&self, genre_id: Id) -> Vec<Id> ⓘ

Releases holding at least one track of a genre, or carrying it whole.

Source

pub fn tracks_of_label(&self, label_id: Id) -> Vec<Id> ⓘ

Tracks published under a label, through the releases carrying it.

Source

pub fn releases_of_label(&self, label_id: Id) -> Vec<Id> ⓘ

Releases published under a label.

Source

pub fn artists_in_role(&self, role: &str) -> Vec<(Id, usize)>

Everyone credited in a role, with how many credits each holds.

This is the inverse of the artist page: that one answers “what did this person do”, this one answers “who does this in my library”. The whole point of storing roles rather than a bare artist column is that the question can be asked in both directions.

Sorted by number of credits, then by sort name, so the answer is stable and the most present come first.

Source

pub fn tracks_of_artist_in_role(&self, artist_id: Id, role: &str) -> Vec<Id> ⓘ

Tracks on which an artist holds one particular role.

The other direction of Catalog::artists_in_role, one person at a time: not “who produces here” but “what did this person produce”. The artist page separates performing from writing; this goes one step finer, down to the single role.

album is credited on the release, not on its tracks, so asking for it yields every track of the releases they sign — otherwise the answer would be empty for the one role every album artist holds.

Source

pub fn roles_of_artist(&self, artist_id: Id) -> Vec<(&str, usize)>

The roles one artist holds, with how many credits each.

What makes an empty answer readable: told that nobody is credited a given way, the user has to be able to see what this person is credited as.

Source

pub fn roles_in_use(&self) -> Vec<&str>

Every role actually used in this catalog, in the order they are shown.

Read from the credits rather than from a fixed list: a role that came from a tag nobody anticipated is still a role, and it must be offerable.

Source

pub fn tracks_with_comment(&self, text: &str) -> Vec<Id> ⓘ

Tracks whose file carries a comment containing this text.

The comment belongs to the file, not to the track: it is free text a user wrote, and it survives in the raw tags exactly as it was typed. Matching is done on the normalized form, so accents and case are no obstacle — a comment is prose, and prose is typed carelessly.

Source

pub fn lyrics_of_track(&self, track_id: Id) -> Option<Lyrics>

The words of a track: the tag that carries them, or the .lrc beside the file.

The one place that decides which of the two wins. The tag is preferred, and costs nothing since raw tags are in the catalog; the sidecar is opened only when the tag holds none, and only for the tracks that have one. Three callers ask this question — the track page, the lyrics: field of the grammar, search --lyrics — and three answers that could disagree about precedence is two too many.

Source

pub fn tracks_with_lyric(&self, text: &str) -> Vec<(Id, String)>

The tracks whose words carry this text, with the line that carries it.

The line, not the song: a table cell holding four hundred lines is a table nobody can read, and what somebody searching for “all aboard” wants to see is the line they half-remembered, in the shape they half-remembered it.

Source

pub fn comment_of_track(&self, track_id: Id) -> Option<&str>

The comment carried by the file behind a track, when there is one.

Trait Implementations§

Source§

impl Clone for Catalog

Source§

fn clone(&self) -> Catalog

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Catalog

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Catalog

Source§

fn default() -> Catalog

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<S> FromSample<S> for S

§

fn from_sample_(s: S) -> S

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

§

fn into_sample(self) -> T

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

§

fn to_sample_(self) -> U

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,