195 lines
7.6 KiB
Swift
195 lines
7.6 KiB
Swift
//
|
|
// Track.swift
|
|
// Tag for iTunes
|
|
//
|
|
// Created by Kim Wittenburg on 30.05.15.
|
|
// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
|
|
//
|
|
|
|
import Cocoa
|
|
|
|
/// Represents a track of the
|
|
/// [Search API](https://www.apple.com/itunes/affiliates/resources/documentation/itunes-store-web-service-search-api.html).
|
|
public class Track: iTunesType {
|
|
|
|
// MARK: Types
|
|
|
|
public enum Tag: String {
|
|
case Name = "name", Artist = "artist", Year = "year", TrackNumber = "trackNumber", TrackCount = "trackCount", DiscNumber = "discNumber", DiscCount = "discCount", Genre = "genre", AlbumName = "album", AlbumArtist = "albumArtist"
|
|
case SortName = "sortName", SortArtist = "sortArtist", SortAlbumName = "sortAlbum", SortAlbumArtist = "sortAlbumArtist", Composer = "composer", SortComposer = "sortComposer", Comment = "comment"
|
|
|
|
/// Returns `true` for tags that are returned from the
|
|
/// [Search API](https://www.apple.com/itunes/affiliates/resources/documentation/itunes-store-web-service-search-api.html).
|
|
public var isReturnedBySearchAPI: Bool {
|
|
switch self {
|
|
case .Name, .Artist, .Year, .TrackNumber, .TrackCount, .DiscNumber, .DiscCount, .Genre, .AlbumName, .AlbumArtist:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
public var clearable: Bool {
|
|
switch self {
|
|
case .Year, .TrackNumber, .TrackCount, .DiscNumber, .DiscCount:
|
|
return false
|
|
default:
|
|
return true
|
|
}
|
|
}
|
|
|
|
/// Returns a string identifying the respective tag that can be displayed
|
|
/// to the user.
|
|
public var localizedName: String {
|
|
return NSLocalizedString("Tag: \(self.rawValue)", comment: "")
|
|
}
|
|
|
|
/// Returns an array of all tags.
|
|
public static var allTags: [Tag] {
|
|
return [.Name, .Artist, .Year, .TrackNumber, .TrackCount, .DiscNumber, .DiscCount, .Genre, .AlbumName, .AlbumArtist, .SortName, .SortArtist, .SortAlbumName, .SortAlbumArtist, .Composer, .SortComposer, .Comment]
|
|
}
|
|
|
|
}
|
|
|
|
// MARK: Properties
|
|
|
|
public let id: iTunesId
|
|
|
|
public let name: String
|
|
|
|
public let censoredName: String
|
|
|
|
public let artistName: String
|
|
|
|
public let releaseDate: NSDate
|
|
|
|
public let trackNumber: Int
|
|
|
|
public let trackCount: Int
|
|
|
|
public let discNumber: Int
|
|
|
|
public let discCount: Int
|
|
|
|
public let genre: String
|
|
|
|
public internal(set) weak var album: Album!
|
|
|
|
/// These tracks will be changed, if `save()` is called.
|
|
public var associatedTracks = [iTunesTrack]()
|
|
|
|
// MARK: Initializers
|
|
|
|
public required init(data: [iTunesAPI.Field: AnyObject]) {
|
|
id = data[.TrackId] as! UInt
|
|
name = data[.TrackName] as! String
|
|
censoredName = data[.TrackCensoredName] as! String
|
|
artistName = data[.ArtistName] as! String
|
|
releaseDate = iTunesAPI.sharedDateFormatter.dateFromString(data[.ReleaseDate] as! String)!
|
|
trackNumber = data[.TrackNumber] as! Int
|
|
trackCount = data[.TrackCount] as! Int
|
|
discNumber = data[.DiscNumber] as! Int
|
|
discCount = data[.DiscCount] as! Int
|
|
genre = data[.PrimaryGenreName] as! String
|
|
}
|
|
|
|
public static var requiredFields: [iTunesAPI.Field] {
|
|
return [.TrackId, .TrackName, .TrackCensoredName, .ArtistName, .ReleaseDate, .TrackNumber, .TrackCount, .DiscNumber, .DiscCount, .PrimaryGenreName]
|
|
}
|
|
|
|
// MARK: Methods
|
|
|
|
/// Saves the track. This means that its properties are applied to every
|
|
/// `iTunesTrack` in its `associatedTracks`.
|
|
///
|
|
/// This method respects the user's preferences (See `Preferences` class).
|
|
public func save() {
|
|
saveToTracks(associatedTracks)
|
|
}
|
|
|
|
/// Applies the receiver's properties to the specified tracks.
|
|
///
|
|
/// This method respects the user's preferences (See `Preferences` class).
|
|
public func saveToTracks(tracks: [iTunesTrack]) {
|
|
for track in tracks {
|
|
saveToTrack(track)
|
|
}
|
|
}
|
|
|
|
/// Applies the receiver's properties to the specified `track`.
|
|
///
|
|
/// This method respects the user's preferences (See `Preferences` class).
|
|
public func saveToTrack(track: iTunesTrack) {
|
|
let components = NSCalendar.currentCalendar().components(.Year, fromDate: releaseDate)
|
|
let trackName = Preferences.sharedPreferences.useCensoredNames ? censoredName : name
|
|
saveTag(.Name, toTrack: track, value: trackName)
|
|
saveTag(.Artist, toTrack: track, value: artistName)
|
|
saveTag(.Year, toTrack: track, value: components.year)
|
|
saveTag(.TrackNumber, toTrack: track, value: trackNumber)
|
|
saveTag(.TrackCount, toTrack: track, value: trackCount)
|
|
saveTag(.DiscNumber, toTrack: track, value: discNumber)
|
|
saveTag(.DiscCount, toTrack: track, value: discCount)
|
|
saveTag(.Genre, toTrack: track, value: genre)
|
|
let albumName = Preferences.sharedPreferences.useCensoredNames ? album.censoredName : album.name
|
|
saveTag(.AlbumName, toTrack: track, value: albumName)
|
|
saveTag(.AlbumArtist, toTrack: track, value: album.artistName)
|
|
saveTag(.SortName, toTrack: track, value: nil)
|
|
saveTag(.SortArtist, toTrack: track, value: nil)
|
|
saveTag(.SortAlbumName, toTrack: track, value: nil)
|
|
saveTag(.SortAlbumArtist, toTrack: track, value: nil)
|
|
saveTag(.Composer, toTrack: track, value: nil)
|
|
saveTag(.SortComposer, toTrack: track, value: nil)
|
|
saveTag(.Comment, toTrack: track, value: nil)
|
|
|
|
// TODO: Deal with artworks
|
|
// if Preferences.sharedPreferences.clearArtworks {
|
|
// track.artworks().removeAllObjects()
|
|
// }
|
|
}
|
|
|
|
private func saveTag(tag: Tag, toTrack track: iTunesTrack, value: AnyObject?) {
|
|
switch Preferences.sharedPreferences.tagSavingBehaviors[tag]! {
|
|
case .Save:
|
|
track.setValue(value, forKey: tag.rawValue)
|
|
case .Clear:
|
|
track.setValue("", forKey: tag.rawValue)
|
|
case .Ignore:
|
|
break
|
|
}
|
|
}
|
|
|
|
/// Returns `true` if all `associatedTrack`s contain the same values as the
|
|
/// `Track` instance.
|
|
public var saved: Bool {
|
|
let components = NSCalendar.currentCalendar().components(.Year, fromDate: releaseDate)
|
|
for track in associatedTracks {
|
|
let trackName = Preferences.sharedPreferences.useCensoredNames ? censoredName : name
|
|
let albumName = Preferences.sharedPreferences.useCensoredNames ? album.censoredName : album.name
|
|
let options = Preferences.sharedPreferences.caseSensitive ? [] : NSStringCompareOptions.CaseInsensitiveSearch
|
|
guard track.name.compare(trackName, options: options, range: nil, locale: nil) == .OrderedSame else {
|
|
return false
|
|
}
|
|
guard track.album.compare(albumName, options: options, range: nil, locale: nil) == .OrderedSame else {
|
|
return false
|
|
}
|
|
guard track.artist == artistName && track.year == components.year && track.trackNumber == trackNumber && track.trackCount == trackCount && track.discNumber == discNumber && track.discCount == discCount && track.genre == genre && track.albumArtist == album.artistName && track.composer == "" else {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
}
|
|
|
|
extension Track: Hashable {
|
|
|
|
public var hashValue: Int {
|
|
return Int(id)
|
|
}
|
|
|
|
}
|
|
|
|
public func ==(lhs: Track, rhs: Track) -> Bool {
|
|
return lhs.id == rhs.id
|
|
}
|