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 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
use crate::error::Error;
use crate::script_controller::{ParamType, ScriptController};
use serde::Deserialize;
/// Provides data related to a specific Track as well as its artworks.
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Track {
/// The class of the Track
pub class: TrackKind,
/// The id of the item
pub id: i32,
/// The index of the item in internal application order
pub index: i32,
/// The name of the item
pub name: String,
/// The id of the item as a hexadecimal string. This id does not change over time.
#[serde(rename = "persistentID")]
pub persistent_id: String,
/// The album name of the track
pub album: String,
/// The album artist of the track
pub album_artist: String,
/// Is the album for this track disliked?
pub album_disliked: bool,
/// Is the album for this track loved?
pub album_loved: bool,
/// The rating of the album for this track (0 to 100)
pub album_rating: Option<i16>,
/// The rating kind of the album rating for this track
pub album_rating_kind: Option<Kind>,
/// The artist/source of the track
pub artworks: Option<Vec<Artwork>>,
/// The artist of the track
pub artist: String,
/// The bit rate of the track (in kbps)
pub bit_rate: Option<i16>,
/// The bookmark time of the track in seconds
pub bookmark: i8,
/// Is the playback position for this track remembered?
pub bookmarkable: bool,
/// The tempo of this track in beats per minute
pub bpm: i16,
/// The category of the track
pub category: String,
/// The iCloud status of the track
pub cloud_status: Option<CloudStatus>,
/// Freeform notes about the track
pub comment: String,
/// Is this track from a compilation album?
pub compilation: bool,
/// The composer of the track
pub composer: String,
/// The common, unique ID for this track. If two tracks in different playlists have the same database ID, they are sharing the same data.
#[serde(rename = "databaseID")]
pub database_id: i32,
/// The date the track was added to the playlist
pub date_added: String,
/// The description of the track
pub description: String,
/// Is this track disliked?
pub disliked: bool,
/// The Apple ID of the person who downloaded this track
#[serde(rename = "downloaderAppleID")]
pub downloader_apple_id: Option<String>,
/// The name of the person who downloaded this track
pub downloader_name: Option<String>,
/// The length of the track in seconds
pub duration: f64,
/// Is this track checked for playback?
pub enabled: bool,
/// The episode ID of the track
#[serde(rename = "episodeID")]
pub episode_id: Option<String>,
/// The episode number of the track
pub episode_number: i16,
/// The name of the EQ preset of the track
pub eq: String,
/// The stop time of the track in seconds
pub finish: f64,
/// Is this track from a gapless album?
pub gapless: Option<bool>,
/// The music/audio genre (category) of the track
pub genre: String,
/// The grouping (piece) of the track. Generally used to denote movements within a classical work.
pub grouping: String,
/// A text description of the track
pub kind: Option<String>,
/// The long description of the track
pub long_description: Option<String>,
/// Is this track loved?
pub loved: bool,
/// The lyrics of the track
pub lyrics: Option<String>,
/// The media kind of the track
pub media_kind: MediaKind,
/// The modification date of the content of this track
pub modification_date: Option<String>,
/// The movement name of the track
pub movement: Option<String>,
/// The total number of movements in the work
pub movement_count: i16,
/// The index of the movement in the work
pub movement_number: i16,
/// Number of times this track has been played
pub played_count: i16,
/// The date and time this track was last played
pub played_date: Option<String>,
/// The Apple ID of the person who purchased this track
#[serde(rename = "purchaserAppleID")]
pub purchaser_apple_id: Option<String>,
/// The name of the person who purchased this track
pub purchaser_name: Option<String>,
/// The rating of this track (0 to 100)
pub rating: i16,
/// The rating kind of this track
pub rating_kind: Option<Kind>,
/// The release date of this track
pub release_date: Option<String>,
/// The sample rate of the track (in Hz)
pub sample_rate: Option<i32>,
/// The season number of the track
pub season_number: Option<i16>,
/// Is this track included when shuffling?
pub shufflable: bool,
/// Number of times this track has been skipped
pub skipped_count: i16,
/// The date and time this track was last skipped
pub skipped_date: Option<String>,
/// The show name of the track
pub show: Option<String>,
/// Override string to use for the track when sorting by album
pub sort_album: Option<String>,
/// Override string to use for the track when sorting by artist
pub sort_artist: Option<String>,
/// Override string to use for the track when sorting by album artist
pub sort_album_artist: Option<String>,
/// Override string to use for the track when sorting by name
pub sort_name: Option<String>,
/// Override string to use for the track when sorting by composer
pub sort_composer: Option<String>,
/// Override string to use for the track when sorting by show name
pub sort_show: Option<String>,
/// The size of the track (in bytes)
pub size: Option<i64>,
/// The start time of the track in seconds
pub start: f64,
/// The length of the track in MM:SS format
pub time: String,
/// The total number of tracks on the source album
pub track_count: i16,
/// The index of the track on the source album
pub track_number: i16,
/// Is this track unplayed?
pub unplayed: bool,
/// Relative volume adjustment of the track (-100% to 100%)
pub volume_adjustment: i16,
/// The work name of the track
pub work: Option<String>,
/// The year the track was recorded/released
pub year: i16,
}
impl Track {
pub fn fetch_artworks(&mut self) -> Result<(), Error> {
match ScriptController.execute_script::<Vec<Artwork>>(
ParamType::Artworks,
Some(self.id),
None,
) {
Ok(data) => {
self.artworks = Some(data);
Ok(())
}
Err(err) => Err(err),
}
}
/// Reveals and selects Track in Apple Music.
pub fn reveal_in_player(&self) -> Result<(), Error> {
let cmd = format!(
"Application('Music').reveal(Application('Music').tracks.byId({}))",
self.id
);
let _ = ScriptController.execute(cmd.as_str(), None);
Ok(())
}
/// Triggers a download on Apple Music Player for the Track.
pub fn download(&self) -> Result<(), Error> {
let cmd = format!(
"Application('Music').download(Application('Music').tracks.byId({}))",
self.id
);
let _ = ScriptController.execute(cmd.as_str(), None);
Ok(())
}
/// Loves / "Unloves" a Track.
pub fn set_loved(&self, value: bool) -> Result<(), Error> {
let cmd = format!(
"Application('Music').tracks.byId({}).loved = {}",
self.id, value
);
let _ = ScriptController.execute(cmd.as_str(), None);
Ok(())
}
/// Dislikes / "Undislikes" a Track.
pub fn set_disliked(&self, value: bool) -> Result<(), Error> {
let cmd = format!(
"Application('Music').tracks.byId({}).disliked = {}",
self.id, value
);
let _ = ScriptController.execute(cmd.as_str(), None);
Ok(())
}
}
/// Data for a given Artwork.
#[derive(Deserialize, Debug)]
pub struct Artwork {
/// The class of the item.
pub class: String,
/// Data for the artwork, in the form of a picture.
pub data: Option<String>,
/// Description of artwork as a string.
pub description: Option<String>,
/// Was this artwork downloaded by Apple Music ?
pub downloaded: bool,
/// The data format for this piece of artwork.
pub format: Option<String>,
/// Kind or purpose of this piece of artwork.
pub kind: i32,
/// Data for this artwork, in original format.
pub raw_data: String,
}
/// Type of Rating: User-made or Computed.
#[derive(Deserialize, Debug)]
#[serde(rename_all = "lowercase")]
pub enum Kind {
User,
Computed,
}
/// iCloud status for Track.
#[derive(Deserialize, Debug)]
#[serde(rename_all = "lowercase")]
pub enum CloudStatus {
Unknown,
Purchased,
Matched,
Uploaded,
Ineligible,
Removed,
Error,
Duplicate,
Subscription,
Prerelease,
#[serde(rename = "no longer available")]
NoLongerAvailable,
NotUploaded,
}
/// Type of Media: Song, MusicVideo or Unknown.
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub enum MediaKind {
Song,
MusicVideo,
Unknown,
}
/// Type of Track: From an URL, a File, or Shared.
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub enum TrackKind {
SharedTrack,
FileTrack,
UrlTrack,
}