9e1dbfd530
Closes #108
181 lines
4.3 KiB
Elixir
181 lines
4.3 KiB
Elixir
defmodule MusicBrainz.Release do
|
|
@moduledoc false
|
|
|
|
@enforce_keys [
|
|
:id,
|
|
:title,
|
|
:disambiguation,
|
|
:packaging,
|
|
:artists,
|
|
:date,
|
|
:barcode,
|
|
:catalog_number,
|
|
:country,
|
|
:media
|
|
]
|
|
defstruct [
|
|
:id,
|
|
:title,
|
|
:disambiguation,
|
|
:packaging,
|
|
:artists,
|
|
:date,
|
|
:barcode,
|
|
:catalog_number,
|
|
:country,
|
|
:media
|
|
]
|
|
|
|
@type t :: %__MODULE__{
|
|
id: String.t(),
|
|
title: String.t(),
|
|
disambiguation: String.t() | nil,
|
|
packaging: String.t() | nil,
|
|
artists: [Artist.t()],
|
|
date: String.t() | nil,
|
|
barcode: String.t() | nil,
|
|
catalog_number: String.t(),
|
|
country: String.t() | nil,
|
|
media: [Medium.t()]
|
|
}
|
|
|
|
defmodule Artist do
|
|
@moduledoc false
|
|
|
|
@enforce_keys [:id, :name, :sort_name]
|
|
defstruct [:id, :name, :sort_name]
|
|
|
|
@type t :: %__MODULE__{
|
|
id: String.t(),
|
|
name: String.t(),
|
|
sort_name: String.t()
|
|
}
|
|
end
|
|
|
|
defmodule Medium do
|
|
@moduledoc false
|
|
|
|
@enforce_keys [:title, :format, :number, :track_count, :tracks]
|
|
defstruct [:title, :format, :number, :track_count, :tracks]
|
|
|
|
@type t :: %__MODULE__{
|
|
title: String.t() | nil,
|
|
format: String.t() | nil,
|
|
number: non_neg_integer(),
|
|
track_count: non_neg_integer(),
|
|
tracks: [MusicBrainz.Release.Track.t()]
|
|
}
|
|
end
|
|
|
|
defmodule Track do
|
|
@moduledoc false
|
|
|
|
@enforce_keys [:id, :title, :artists, :length, :number, :position]
|
|
defstruct [:id, :title, :artists, :length, :number, :position]
|
|
|
|
@type t :: %__MODULE__{
|
|
id: String.t(),
|
|
title: String.t(),
|
|
artists: [MusicBrainz.Release.Artist.t()],
|
|
length: non_neg_integer() | nil,
|
|
number: String.t(),
|
|
position: non_neg_integer()
|
|
}
|
|
end
|
|
|
|
@spec media_count(t()) :: non_neg_integer()
|
|
def media_count(release) do
|
|
Enum.count(release.media)
|
|
end
|
|
|
|
@spec get_medium(t(), non_neg_integer()) :: Medium.t() | nil
|
|
def get_medium(release, medium_number) do
|
|
Enum.find(release.media, fn m -> m.number == medium_number end)
|
|
end
|
|
|
|
@spec medium_duration(Medium.t()) :: non_neg_integer()
|
|
def medium_duration(medium) do
|
|
Enum.sum_by(medium.tracks, fn track -> track.length || 0 end)
|
|
end
|
|
|
|
@spec medium_tracks(t(), non_neg_integer()) :: [Track.t()]
|
|
def medium_tracks(release, medium_number) do
|
|
case Enum.find(release.media, fn m -> m.number == medium_number end) do
|
|
nil -> []
|
|
medium -> medium.tracks
|
|
end
|
|
end
|
|
|
|
@spec release_duration(t()) :: non_neg_integer()
|
|
def release_duration(release) do
|
|
Enum.sum_by(release.media, fn medium -> medium_duration(medium) end)
|
|
end
|
|
|
|
@spec tracks(t()) :: [Track.t()]
|
|
def tracks(release) do
|
|
Enum.flat_map(release.media, fn medium -> medium.tracks end)
|
|
end
|
|
|
|
@spec from_api_response(map()) :: t()
|
|
def from_api_response(r) do
|
|
%__MODULE__{
|
|
id: r["id"],
|
|
title: r["title"],
|
|
disambiguation: r["disambiguation"],
|
|
packaging: r["packaging"],
|
|
artists: parse_artists(r["artist-credit"] || []),
|
|
date: r["date"],
|
|
barcode: r["barcode"],
|
|
catalog_number: parse_catalog_number(r["label-info"] || []),
|
|
country: r["country"],
|
|
media: parse_media(r["media"] || [])
|
|
}
|
|
end
|
|
|
|
@spec thumb_url(t()) :: String.t()
|
|
def thumb_url(release) do
|
|
"https://coverartarchive.org/release/#{release.id}/front-250"
|
|
end
|
|
|
|
defp parse_media(media) do
|
|
Enum.map(media, fn m ->
|
|
%Medium{
|
|
title: m["title"],
|
|
format: m["format"],
|
|
number: m["position"],
|
|
track_count: m["track-count"],
|
|
tracks: parse_tracks(m["tracks"] || [])
|
|
}
|
|
end)
|
|
end
|
|
|
|
defp parse_tracks(tracks) do
|
|
Enum.map(tracks, fn t ->
|
|
%Track{
|
|
id: t["id"],
|
|
title: t["title"],
|
|
artists: parse_artists(t["recording"]["artist-credit"]),
|
|
length: t["length"],
|
|
number: t["number"],
|
|
position: t["position"]
|
|
}
|
|
end)
|
|
end
|
|
|
|
defp parse_artists(artists) do
|
|
Enum.map(artists, fn a ->
|
|
%Artist{
|
|
id: a["artist"]["id"],
|
|
name: a["artist"]["name"],
|
|
sort_name: a["artist"]["sort-name"]
|
|
}
|
|
end)
|
|
end
|
|
|
|
defp parse_catalog_number(label_infos) do
|
|
Enum.map_join(label_infos, ", ", fn li ->
|
|
li["catalog-number"]
|
|
end)
|
|
end
|
|
end
|