1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
//! Data models for songs.
//!
//! Visit the [Genius documentation](https://docs.genius.com/#songs-h2) for more context.
#[cfg(feature = "catchall")]
use std::collections::HashMap;

use serde::{Deserialize, Serialize};

#[cfg(feature = "catchall")]
use serde_json::Value;

use super::{
    Annotation, ArtistCoreNoMetadata, ReferentCore, SongMetadata, Text, UserCore,
    UserInteractionMetadata,
};

/// A song response.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct SongResponse {
    /// Song data.
    pub song: Song,
}

/// Song data.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct Song {
    /// Apple Music ID.
    pub apple_music_id: Option<String>,
    /// Apple Music player URL.
    pub apple_music_player_url: String,
    /// Current user metadata.
    pub current_user_metadata: SongMetadata,
    /// Song description.
    pub description: Text,
    /// Embeddable content.
    pub embed_content: String,
    /// If the song has a featured video.
    pub featured_video: bool,
    /// The song's language.
    pub language: String,
    /// Reason for a lyrics placeholder.
    pub lyrics_placeholder_reason: (),
    /// Recording location.
    pub recording_location: Option<String>,
    /// Release date.
    pub release_date: Option<String>,
    /// Associated album.
    pub album: Album,
    /// Custom performances.
    pub custom_performances: Vec<Performance>,
    /// Song description as an annotation.
    pub description_annotation: DescriptionAnnotation,
    /// User who has marked the song lyrics as complete.
    pub lyrics_marked_complete_by: Option<UserCore<UserInteractionMetadata>>,
    /// Staff who has marked the song lyrics as approved.
    pub lyrics_marked_staff_approved_by: Option<UserCore<UserInteractionMetadata>>,
    /// Associated media.
    pub media: Vec<Media>,
    /// Song producers.
    pub producer_artists: Vec<ArtistCoreNoMetadata>,
    /// Song relationships.
    pub song_relationships: Vec<SongRelationship>,
    /// Translation songs.
    pub translation_songs: Vec<TranslationSong>,
    /// Verified annotators.
    pub verified_annotations_by: Vec<UserCore<UserInteractionMetadata>>,
    /// Verified contributors.
    pub verified_contributors: Vec<Contribution>,
    /// Providers of verified lyrics.
    pub verified_lyrics_by: Vec<()>,
    /// Song writers.
    pub writer_artists: Vec<ArtistCoreNoMetadata>,
    /// Core song data.
    #[serde(flatten)]
    pub core: SongCore<SongStats>,
    /// Extra data.
    #[cfg(feature = "catchall")]
    #[serde(flatten)]
    pub extra: HashMap<String, Value>,
}

/// Song media.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type")]
#[serde(rename_all = "lowercase")]
pub enum Media {
    /// Song audio.
    Audio(Audio),
    /// Song video.
    Video(Video),
}

impl Default for Media {
    fn default() -> Self {
        Media::Audio(Audio::default())
    }
}

/// Song audio.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct Audio {
    /// The user on the provider's platform providing the audio.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub attribution: Option<String>,
    /// Native URI of the song in the provider's platform.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub native_uri: Option<String>,
    /// The audio provider platform.
    pub provider: String,
    /// URL to the audio.
    pub url: String,
}

/// Song video.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct Video {
    /// The video provider platform.
    pub provider: String,
    /// URL to the video.
    pub url: String,
    /// The start time of the video.
    pub start: u32,
}

/// Song relationships.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct SongRelationship {
    /// Internal relationship type field.
    /// Included to stay consistent when serializing.
    #[serde(rename = "type")]
    rel_type: RelationshipType,
    /// The type of relationship.
    pub relationship_type: RelationshipType,
    /// URL to the page of relationships.
    pub url: Option<String>,
    /// Related songs.
    pub songs: Vec<SongCoreWithRDC<SongCoreStats>>,
}

/// A relationship between songs.
#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum RelationshipType {
    /// Samples another song.
    Samples,
    /// Sampled in another song.
    SampledIn,
    /// Interpolates another song.
    Interpolates,
    /// Interpolated by another song.
    InterpolatedBy,
    /// Cover of another song.
    CoverOf,
    /// Covered by another song.
    CoveredBy,
    /// Remix of another song.
    RemixOf,
    /// Remixed by another song.
    RemixedBy,
    /// Live version of another song.
    LiveVersionOf,
    /// Performed live as another song.
    PerformedLiveAs,
    /// Translation of another song.
    TranslationOf,
    /// Translated by another song.
    Translations,
    /// Unknown relationship.
    #[default]
    Unknown,
}

/// Annotation of a song description.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct DescriptionAnnotation {
    /// Referent information.
    #[serde(flatten)]
    pub referent: ReferentCore,
    /// Annotations.
    pub annotations: Vec<Annotation>,
}

/// Information about a contribution.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct Contribution {
    /// Contributions made.
    pub contributions: Vec<String>,
    /// Artist profile associated with the contributor.
    pub artist: ArtistCoreNoMetadata,
    /// User profile associated with the contributor.
    pub user: UserCore<UserInteractionMetadata>,
}

/// Song statistics.
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
pub struct SongStats {
    /// Total number of accepted annotations.
    pub accepted_annotations: u32,
    /// Total number of contributors.
    pub contributors: u32,
    /// Total number of IQ earners.
    pub iq_earners: u32,
    /// Total number of transcribers.
    pub transcribers: u32,
    /// Total number of verified annotations.
    pub verified_annotations: u32,
    /// Core statistics.
    #[serde(flatten)]
    pub core: SongCoreStats,
}

/// Core song statistics.
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
pub struct SongCoreStats {
    /// Total number of concurrents.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub concurrents: Option<u16>,
    /// Total number of page views.
    #[serde(rename = "pageviews", skip_serializing_if = "Option::is_none")]
    pub page_views: Option<u32>,
    /// Total number of unreviewed annotations.
    pub unreviewed_annotations: u32,
    /// Whether the song is hot.
    pub hot: bool,
}

/// A custom performance.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct Performance {
    /// A descriptor of the performance.
    pub label: String,
    /// Artists associated with the performance.
    pub artists: Vec<ArtistCoreNoMetadata>,
}

/// An album.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct Album {
    /// Genius API path to the album.
    pub api_path: String,
    /// URL for the cover art.
    pub cover_art_url: String,
    /// Full title.
    pub full_title: String,
    /// Genius ID.
    pub id: u32,
    /// Name of the album.
    pub name: String,
    /// A display-ready release date.
    pub release_date_for_display: String,
    /// Genius URL to the album.
    pub url: String,
    /// Album's artist.
    pub artist: ArtistCoreNoMetadata,
}

/// Song data with release date components.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct SongCoreWithRDC<S> {
    /// The song's release date, split into components.
    pub release_date_components: Option<DateComponents>,
    /// Core song data.
    #[serde(flatten)]
    pub core: SongCore<S>,
}

/// Core song data.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct SongCore<S> {
    /// Total number of annotations.
    pub annotation_count: u32,
    /// Artist names.
    pub artist_names: String,
    /// Full title.
    pub full_title: String,
    /// URL to the header thumbnail image.
    pub header_image_thumbnail_url: String,
    /// URL to the header image.
    pub header_image_url: String,
    /// Genius ID of the lyrics owner.
    pub lyrics_owner_id: u32,
    /// Total number of pyongs.
    pub pyongs_count: Option<u32>,
    /// URL to the page of relationships.
    pub relationships_index_url: String,
    /// Display-ready release date.
    pub release_date_for_display: Option<String>,
    /// Display-ready release date, with abbreviated month.
    pub release_date_with_abbreviated_month_for_display: Option<String>,
    /// URL to the song art thumbnail image.
    pub song_art_image_thumbnail_url: String,
    /// URL to the song art image.
    pub song_art_image_url: String,
    /// Song stats.
    pub stats: S,
    /// Title with featured artists.
    pub title_with_featured: String,
    /// Featured artists.
    pub featured_artists: Vec<ArtistCoreNoMetadata>,
    /// The song's primary artist.
    pub primary_artist: ArtistCoreNoMetadata,
    /// Essential song data.
    #[serde(flatten)]
    pub essential: SongEssential,
}

/// A date by its components.
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
pub struct DateComponents {
    /// The year.
    pub year: u16,
    /// The month.
    pub month: Option<u8>,
    /// The day.
    pub day: Option<u8>,
}

/// A translation song.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct TranslationSong {
    /// The language of the translation song.
    pub language: String,
    /// Essential song data.
    #[serde(flatten)]
    pub essential: SongEssential,
}

/// Essential song data.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct SongEssential {
    /// Genius API path to the song.
    pub api_path: String,
    /// Genius ID.
    pub id: u32,
    /// State of the lyrics.
    pub lyrics_state: String,
    /// Genius path to the song.
    pub path: String,
    /// Song title.
    pub title: String,
    /// Genius URL to the song.
    pub url: String,
}