apple_music_library 0.2.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/Gemfile.lock +1 -1
- data/README.md +9 -0
- data/apple_music_library.gemspec +1 -1
- data/lib/apple_music_library/album.rb +15 -1
- data/lib/apple_music_library/artist.rb +29 -3
- data/lib/apple_music_library/genre.rb +17 -0
- data/lib/apple_music_library/library.rb +33 -81
- data/lib/apple_music_library/playlist.rb +40 -18
- data/lib/apple_music_library/playlist_folder.rb +55 -0
- data/lib/apple_music_library/track.rb +42 -12
- data/lib/apple_music_library/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28f3fe7d3df7d724f7e7290f9eb6c33e2dae08d22e60ed07dfeb87c9bda9c283
|
4
|
+
data.tar.gz: 302301b2f8dd1826f71d18474fa15dfa804babf481b46ab4db99694364e0342f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5bcb31d7d2326fe4d6f614a6a29a6c69b4e47e349a235b47234afc97f10618630eb4ae995bfc2c402fe2629d080e6834067cc2b6606ba22132c1662af9d19c1e
|
7
|
+
data.tar.gz: d1785f58aab9a2a75d1c77ce165f37307141af7dc25833d12f669dbc0c201a9633384187c9d71b36e3a5e7a8c1f7a8696d8e14197b826f5538d5b49e3310cd82
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## [Unreleased]
|
4
|
+
- Ability to print out playlist folder hierarchy
|
5
|
+
|
6
|
+
## 0.5.0 - 2022-03-11
|
7
|
+
### Added
|
8
|
+
- Basic functionality for track ratings via the #rating, #star_rating, and #loved
|
9
|
+
|
10
|
+
## 0.4.0 - 2022-03-11
|
11
|
+
### Added
|
12
|
+
- Basic functionality for Playlist Folders
|
13
|
+
### Fixed
|
14
|
+
- The #find_by_name methods for Playlists and PlaylistFolders now return a single object when only a single exact match is found (the most common case) but continue to return an array of objects when there are multiple matches.
|
15
|
+
|
16
|
+
## 0.3.0 - 2022-03-10
|
17
|
+
|
18
|
+
### Fixed
|
19
|
+
- Fixed handling of albums, genres, and playlists as accessed via methods on artists/tracks.
|
20
|
+
|
21
|
+
## 0.2.0 - 2022-03-10
|
22
|
+
### Added
|
23
|
+
- Basic functionality to parse a library plist into Track, Album, Artist, Genre, and Playlist objects.
|
24
|
+
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -28,6 +28,12 @@ library = AppleMusicLibrary.new('path/to/Library.xml')
|
|
28
28
|
# Count albums
|
29
29
|
puts library.albums.count
|
30
30
|
|
31
|
+
# Show playlist inside playlist folder
|
32
|
+
playlist_folder = library.playlist_folder('Folder for Testing')
|
33
|
+
playlist_folder.playlists.each do |playlist|
|
34
|
+
puts playlist.name
|
35
|
+
end
|
36
|
+
|
31
37
|
# Show tracks in a specific playlist
|
32
38
|
playlist = library.playlist('XTC Favorites')
|
33
39
|
playlist.tracks.each do |track|
|
@@ -38,6 +44,9 @@ end
|
|
38
44
|
artist = library.artist('XTC')
|
39
45
|
puts artist.tracks.count
|
40
46
|
|
47
|
+
# Get favorite tracks by this artists
|
48
|
+
favorite_tracks = artist.tracks.select{|t| t.loved? || t.star_rating > 3}
|
49
|
+
|
41
50
|
# Display track counts per genre
|
42
51
|
library.genres.each do |genre|
|
43
52
|
puts "#{genre.tracks.count} #{genre.name}"
|
data/apple_music_library.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ["Todd Gehman"]
|
9
9
|
spec.email = ["github@pugetive.com"]
|
10
10
|
|
11
|
-
spec.summary = "Provides a
|
11
|
+
spec.summary = "Provides a Ruby interface to the information stored in an Apple Music (formerly iTunes) Library xml file."
|
12
12
|
# spec.description = "TODO: Write a longer description or delete this line."
|
13
13
|
spec.homepage = "https://github.com/pugetive/apple_music_library"
|
14
14
|
spec.license = "MIT"
|
@@ -5,12 +5,26 @@ module AppleMusicLibrary
|
|
5
5
|
|
6
6
|
attr_reader :artist, :album_name, :tracks
|
7
7
|
|
8
|
+
@@albums = {}
|
9
|
+
|
8
10
|
def initialize(artist, album_name)
|
9
11
|
@artist = artist
|
10
12
|
@album_name = album_name
|
11
13
|
@tracks = []
|
12
14
|
end
|
13
15
|
|
16
|
+
def self.all
|
17
|
+
@@albums.values
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.find_or_create(artist, album_name)
|
21
|
+
key = "#{artist.name}-#{album_name}"
|
22
|
+
if @@albums[key]
|
23
|
+
return @@albums[key]
|
24
|
+
end
|
25
|
+
@@albums[key] = self.new(artist, album_name)
|
26
|
+
end
|
27
|
+
|
14
28
|
def id
|
15
29
|
"#{artist.name}-#{album_name}"
|
16
30
|
end
|
@@ -20,7 +34,7 @@ module AppleMusicLibrary
|
|
20
34
|
end
|
21
35
|
|
22
36
|
def year
|
23
|
-
@year ||= tracks.
|
37
|
+
@year ||= @tracks.sort_by(&:year).last.year
|
24
38
|
end
|
25
39
|
|
26
40
|
end
|
@@ -3,24 +3,50 @@ module AppleMusicLibrary
|
|
3
3
|
|
4
4
|
attr_reader :name
|
5
5
|
|
6
|
+
@@artists = {}
|
7
|
+
|
6
8
|
def initialize(name)
|
7
9
|
@name = name
|
8
10
|
@albums = []
|
11
|
+
@tracks = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.all
|
15
|
+
@@artists.values
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.find_or_create(name)
|
19
|
+
if @@artists[name]
|
20
|
+
return @@artists[name]
|
21
|
+
end
|
22
|
+
@@artists[name] = self.new(name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.find_by_name(artist_name)
|
26
|
+
if @@artists[artist_name]
|
27
|
+
return @@artists[artist_name]
|
28
|
+
end
|
29
|
+
nil
|
9
30
|
end
|
10
31
|
|
11
32
|
def add_album(album)
|
12
|
-
unless albums.include?(album)
|
33
|
+
unless @albums.include?(album)
|
13
34
|
@albums << album
|
14
35
|
end
|
15
36
|
end
|
16
37
|
|
38
|
+
def add_track(track)
|
39
|
+
unless @tracks.include?(track)
|
40
|
+
@tracks << track
|
41
|
+
end
|
42
|
+
end
|
17
43
|
|
18
44
|
def albums
|
19
|
-
@albums.
|
45
|
+
@albums.sort_by(&:year)
|
20
46
|
end
|
21
47
|
|
22
48
|
def tracks
|
23
|
-
@tracks
|
49
|
+
@tracks
|
24
50
|
end
|
25
51
|
|
26
52
|
end
|
@@ -3,11 +3,28 @@ module AppleMusicLibrary
|
|
3
3
|
|
4
4
|
attr_reader :name, :tracks
|
5
5
|
|
6
|
+
@@genres = {}
|
7
|
+
|
6
8
|
def initialize(name)
|
7
9
|
@name = name
|
8
10
|
@tracks = []
|
9
11
|
end
|
10
12
|
|
13
|
+
def self.all
|
14
|
+
@@genres.values
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.find_or_create(name)
|
18
|
+
if @@genres[name]
|
19
|
+
return @@genres[name]
|
20
|
+
end
|
21
|
+
@@genres[name] = self.new(name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.find_by_name(name)
|
25
|
+
@@genres[name]
|
26
|
+
end
|
27
|
+
|
11
28
|
def add_track(track)
|
12
29
|
unless tracks.include?(track)
|
13
30
|
@tracks << track
|
@@ -2,6 +2,7 @@ require_relative 'album'
|
|
2
2
|
require_relative 'artist'
|
3
3
|
require_relative 'genre'
|
4
4
|
require_relative 'playlist'
|
5
|
+
require_relative 'playlist_folder'
|
5
6
|
require_relative 'track'
|
6
7
|
require_relative "utils"
|
7
8
|
require 'plist'
|
@@ -36,53 +37,51 @@ module AppleMusicLibrary
|
|
36
37
|
raise Error, "Failed to parse library xml file [#{e.message}]"
|
37
38
|
end
|
38
39
|
|
39
|
-
@artists_hash = {}
|
40
|
-
@tracks_hash = {}
|
41
|
-
@playlists_hash = {}
|
42
|
-
@albums_hash = {}
|
43
|
-
@genres_hash = {}
|
44
|
-
|
45
|
-
@locations_hash = {}
|
46
|
-
@slugs_hash = {}
|
47
|
-
|
48
40
|
extract_plist_info
|
49
41
|
end
|
50
42
|
|
51
|
-
def
|
52
|
-
@
|
43
|
+
def albums
|
44
|
+
@albums ||= Album.all
|
53
45
|
end
|
54
46
|
|
55
47
|
def artists
|
56
|
-
@
|
48
|
+
@artists ||= Artist.all
|
57
49
|
end
|
58
50
|
|
59
51
|
def artist(artist_name)
|
60
|
-
|
52
|
+
Artist.find_by_name(artist_name)
|
61
53
|
end
|
62
54
|
|
63
|
-
def
|
64
|
-
@
|
55
|
+
def genres
|
56
|
+
@genres ||= Genre.all
|
57
|
+
end
|
58
|
+
|
59
|
+
def genre(genre_name)
|
60
|
+
Genre.find_by_name(genre_name)
|
65
61
|
end
|
66
62
|
|
67
63
|
def playlists
|
68
|
-
@
|
64
|
+
@playlists ||= Playlist.all
|
69
65
|
end
|
70
66
|
|
71
67
|
def playlist(playlist_name)
|
72
|
-
|
68
|
+
Playlist.find_by_name(playlist_name)
|
73
69
|
end
|
74
70
|
|
71
|
+
def playlist_folders
|
72
|
+
@playlist_folders ||= PlaylistFolder.all
|
73
|
+
end
|
75
74
|
|
76
|
-
def
|
77
|
-
|
75
|
+
def playlist_folder(playlist_folder_name)
|
76
|
+
PlaylistFolder.find_by_name(playlist_folder_name)
|
78
77
|
end
|
79
78
|
|
80
|
-
def
|
81
|
-
|
79
|
+
def tracks(filter = nil)
|
80
|
+
filter.present? ? Track.send(filter) : Track.all
|
82
81
|
end
|
83
82
|
|
84
|
-
def
|
85
|
-
|
83
|
+
def track(track_id)
|
84
|
+
Track.find(track_id)
|
86
85
|
end
|
87
86
|
|
88
87
|
def valid?
|
@@ -93,82 +92,35 @@ module AppleMusicLibrary
|
|
93
92
|
tracks.any?
|
94
93
|
end
|
95
94
|
|
96
|
-
def track(track_id)
|
97
|
-
track = @tracks_hash[track_id.to_i]
|
98
|
-
if track.nil?
|
99
|
-
message("Cound not find track with ID [#{track_id}]")
|
100
|
-
message("Searched tracks: [#{@tracks_hash.keys.sort.join(', ')}]")
|
101
|
-
end
|
102
|
-
track
|
103
|
-
end
|
104
|
-
|
105
95
|
private
|
106
96
|
|
107
97
|
def extract_plist_info
|
98
|
+
extract_tracks_from_plist
|
99
|
+
extract_playlists_from_plist
|
100
|
+
end
|
101
|
+
|
102
|
+
def extract_tracks_from_plist
|
108
103
|
non_music_formats = {}
|
109
104
|
plist['Tracks'].each do |track|
|
110
105
|
if MUSIC_FORMATS.include?(track[1]['Kind'])
|
111
|
-
|
112
|
-
# next if track.artist.name == 'NPR'
|
113
|
-
@tracks_hash[track.id] = track
|
114
|
-
# @locations_hash[track.location] = track
|
115
|
-
|
116
|
-
artist = add_artist(track.artist)
|
117
|
-
album = add_track_to_album(track, track.album)
|
118
|
-
artist.add_album(album)
|
119
|
-
|
120
|
-
if track.genre_name.present?
|
121
|
-
genre = add_track_to_genre(track)
|
122
|
-
end
|
106
|
+
Track.new(track[1])
|
123
107
|
else
|
124
108
|
non_music_formats[track[1]['Kind']] = true
|
125
109
|
end
|
126
110
|
end
|
127
111
|
|
128
|
-
plist['Playlists'].each do |playlist_info|
|
129
|
-
playlist = Playlist.new(playlist_info, self)
|
130
|
-
next if playlist.folder?
|
131
|
-
@playlists_hash[playlist.id] = playlist
|
132
|
-
end
|
133
|
-
|
134
112
|
if non_music_formats.any?
|
135
113
|
message("Skipped the following non-music formats:\n#{non_music_formats.keys.join(', ')}")
|
136
114
|
end
|
137
|
-
end
|
138
|
-
|
139
|
-
|
140
|
-
def add_artist(artist)
|
141
|
-
unless @artists_hash[artist.name]
|
142
|
-
@artists_hash[artist.name] = artist
|
143
|
-
end
|
144
|
-
artist
|
145
|
-
end
|
146
|
-
|
147
|
-
def add_track_to_album(track, album)
|
148
|
-
return if @albums_hash[album.id]
|
149
|
-
# message("Creating new artist #{artist.name}")
|
150
|
-
@albums_hash[album.id] = album
|
151
|
-
album.add_track(track)
|
152
|
-
album
|
153
|
-
end
|
154
115
|
|
155
|
-
def find_or_create_album(album)
|
156
|
-
unless @albums_hash[album.id]
|
157
|
-
@albums_hash[album.id] = album
|
158
|
-
end
|
159
|
-
album.artist.add_album(album)
|
160
116
|
end
|
161
117
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
118
|
+
def extract_playlists_from_plist
|
119
|
+
plist['Playlists'].each do |playlist_info|
|
120
|
+
# The distinction between playlists and playlist folders
|
121
|
+
# is made inside the Playlist instantiation
|
122
|
+
Playlist.new(playlist_info)
|
166
123
|
end
|
167
|
-
# message("Creating new artist #{artist.name}")
|
168
|
-
genre = AppleMusicLibrary::Genre.new(track.genre_name)
|
169
|
-
@genres_hash[track.genre_name] = genre
|
170
|
-
genre.add_track(track)
|
171
|
-
genre
|
172
124
|
end
|
173
125
|
|
174
126
|
end
|
@@ -1,17 +1,3 @@
|
|
1
|
-
# <key>Name</key><string>Non-XTC</string>
|
2
|
-
# <key>Description</key><string></string>
|
3
|
-
# <key>Playlist ID</key><integer>79359</integer>
|
4
|
-
# <key>Playlist Persistent ID</key><string>59C95825DF1F0DCC</string>
|
5
|
-
# <key>All Items</key><true/>
|
6
|
-
# <key>Smart Info</key>
|
7
|
-
# <data>
|
8
|
-
# AQEAAwAAAAIAAAAZAAAAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
9
|
-
# AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
10
|
-
# AAAAAA==
|
11
|
-
# </data>
|
12
|
-
# <key>Smart Criteria</key>
|
13
|
-
# <data>
|
14
|
-
|
15
1
|
require 'facets'
|
16
2
|
|
17
3
|
module AppleMusicLibrary
|
@@ -19,26 +5,47 @@ module AppleMusicLibrary
|
|
19
5
|
|
20
6
|
attr_reader :info, :tracks
|
21
7
|
|
8
|
+
@@playlists = {}
|
9
|
+
|
22
10
|
ATTRIBUTES = ['Name',
|
23
11
|
'Description',
|
24
12
|
'Playlist ID',
|
25
13
|
'Playlist Persistent ID',
|
14
|
+
'Parent Persistent ID',
|
26
15
|
'All Items',
|
27
16
|
'Smart Info',
|
28
17
|
'Smart Criteria',
|
29
18
|
'Playlist Items',
|
30
19
|
'Folder']
|
31
20
|
|
32
|
-
def initialize(info
|
21
|
+
def initialize(info)
|
33
22
|
@info = info
|
34
|
-
|
23
|
+
|
24
|
+
if folder?
|
25
|
+
return PlaylistFolder.new(info)
|
26
|
+
end
|
27
|
+
|
35
28
|
@tracks = []
|
36
29
|
|
37
30
|
load_tracks
|
31
|
+
|
32
|
+
@@playlists[id] = self
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.all
|
36
|
+
@@playlists.values
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.find_by_name(playlist_name)
|
40
|
+
results = @@playlists.values.select{|p| p.name == playlist_name}
|
41
|
+
if results.size == 1
|
42
|
+
return results.first
|
43
|
+
end
|
44
|
+
results
|
38
45
|
end
|
39
46
|
|
40
47
|
def id
|
41
|
-
|
48
|
+
playlist_persistent_id
|
42
49
|
end
|
43
50
|
|
44
51
|
ATTRIBUTES.each do |attribute|
|
@@ -57,7 +64,7 @@ module AppleMusicLibrary
|
|
57
64
|
if playlist_items and playlist_items.any?
|
58
65
|
playlist_items.each do |playlist_item|
|
59
66
|
track_id = playlist_item['Track ID']
|
60
|
-
track =
|
67
|
+
track = Track.find(track_id)
|
61
68
|
@tracks << track
|
62
69
|
end
|
63
70
|
end
|
@@ -66,3 +73,18 @@ module AppleMusicLibrary
|
|
66
73
|
|
67
74
|
end
|
68
75
|
end
|
76
|
+
|
77
|
+
# <key>Name</key><string>Non-XTC</string>
|
78
|
+
# <key>Description</key><string></string>
|
79
|
+
# <key>Playlist ID</key><integer>79359</integer>
|
80
|
+
# <key>Playlist Persistent ID</key><string>59C95825DF1F0DCC</string>
|
81
|
+
# <key>All Items</key><true/>
|
82
|
+
# <key>Smart Info</key>
|
83
|
+
# <data>
|
84
|
+
# AQEAAwAAAAIAAAAZAAAAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
85
|
+
# AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
86
|
+
# AAAAAA==
|
87
|
+
# </data>
|
88
|
+
# <key>Smart Criteria</key>
|
89
|
+
# <data>
|
90
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'facets'
|
2
|
+
|
3
|
+
module AppleMusicLibrary
|
4
|
+
class PlaylistFolder
|
5
|
+
|
6
|
+
attr_reader :info
|
7
|
+
|
8
|
+
@@playlist_folders = {}
|
9
|
+
|
10
|
+
def initialize(info)
|
11
|
+
@info = info
|
12
|
+
|
13
|
+
@@playlist_folders[id] = self
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.all
|
17
|
+
@@playlist_folders.values
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.find_by_name(playlist_folder_name)
|
21
|
+
results = @@playlist_folders.values.select{|pf| pf.name == playlist_folder_name}
|
22
|
+
if results.size == 1
|
23
|
+
return results.first
|
24
|
+
end
|
25
|
+
results
|
26
|
+
end
|
27
|
+
|
28
|
+
def id
|
29
|
+
playlist_persistent_id
|
30
|
+
end
|
31
|
+
|
32
|
+
def children
|
33
|
+
playlist_folders.concat(playlists)
|
34
|
+
end
|
35
|
+
|
36
|
+
def playlist_folders
|
37
|
+
@@playlist_folders.values.select{|pf| pf.parent_persistent_id == id}
|
38
|
+
end
|
39
|
+
|
40
|
+
def playlists
|
41
|
+
Playlist.all.select{|p| p.parent_persistent_id == id}
|
42
|
+
end
|
43
|
+
|
44
|
+
Playlist::ATTRIBUTES.each do |attribute|
|
45
|
+
define_method(attribute.to_s.snakecase) do
|
46
|
+
info[attribute]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -2,13 +2,13 @@ require 'facets'
|
|
2
2
|
|
3
3
|
module AppleMusicLibrary
|
4
4
|
class Track
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :artist, :album, :genre
|
6
6
|
|
7
|
-
ATTRIBUTES = ['Track ID',
|
8
|
-
'Name',
|
9
7
|
# 'Artist', The #artist, #album, and #genre methods return objects rather than strings and have methods like #artist_name to retrieve the strings.
|
10
8
|
# 'Album',
|
11
9
|
# 'Genre',
|
10
|
+
ATTRIBUTES = ['Track ID',
|
11
|
+
'Name',
|
12
12
|
'Kind',
|
13
13
|
'Size',
|
14
14
|
'Total Time',
|
@@ -24,6 +24,7 @@ module AppleMusicLibrary
|
|
24
24
|
'Rating',
|
25
25
|
'Album Rating',
|
26
26
|
'Album Rating Computed',
|
27
|
+
'Loved',
|
27
28
|
'Normalization',
|
28
29
|
'Persistent ID',
|
29
30
|
'Track Type',
|
@@ -31,10 +32,32 @@ module AppleMusicLibrary
|
|
31
32
|
'File Folder Count',
|
32
33
|
'Library Folder Count']
|
33
34
|
|
35
|
+
@@tracks = {}
|
36
|
+
|
34
37
|
def initialize(info)
|
35
38
|
@info = info
|
36
|
-
@artist = Artist.
|
37
|
-
@album = Album.
|
39
|
+
@artist = Artist.find_or_create(artist_name)
|
40
|
+
@album = Album.find_or_create(@artist, album_name)
|
41
|
+
@genre = Genre.find_or_create(genre_name)
|
42
|
+
|
43
|
+
@artist.add_track(self)
|
44
|
+
@artist.add_album(@album)
|
45
|
+
@album.add_track(self)
|
46
|
+
@genre.add_track(self)
|
47
|
+
@@tracks[id] = self
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def self.find(track_id)
|
52
|
+
@@tracks[track_id]
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.all
|
56
|
+
@@tracks.values
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.loved
|
60
|
+
@loved ||= self.all.select{|t| t.loved?}
|
38
61
|
end
|
39
62
|
|
40
63
|
def id
|
@@ -42,22 +65,29 @@ module AppleMusicLibrary
|
|
42
65
|
end
|
43
66
|
|
44
67
|
def artist_name
|
45
|
-
info['Artist']
|
68
|
+
@info['Artist']
|
46
69
|
end
|
47
70
|
|
48
71
|
def album_name
|
49
|
-
info['Album']
|
72
|
+
@info['Album']
|
50
73
|
end
|
51
74
|
|
52
75
|
def genre_name
|
53
|
-
info['Genre']
|
76
|
+
@info['Genre']
|
54
77
|
end
|
55
78
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
79
|
+
def star_rating
|
80
|
+
rating / 20
|
81
|
+
end
|
82
|
+
|
83
|
+
def loved?
|
84
|
+
loved
|
85
|
+
end
|
60
86
|
|
87
|
+
ATTRIBUTES.each do |track_attribute|
|
88
|
+
define_method(track_attribute.to_s.snakecase) do
|
89
|
+
@info[track_attribute]
|
90
|
+
end
|
61
91
|
end
|
62
92
|
|
63
93
|
# def slug
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apple_music_library
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Todd Gehman
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-03-
|
11
|
+
date: 2022-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: awesome_print
|
@@ -116,6 +116,7 @@ extensions: []
|
|
116
116
|
extra_rdoc_files: []
|
117
117
|
files:
|
118
118
|
- ".rspec"
|
119
|
+
- CHANGELOG.md
|
119
120
|
- Gemfile
|
120
121
|
- Gemfile.lock
|
121
122
|
- LICENSE.txt
|
@@ -128,6 +129,7 @@ files:
|
|
128
129
|
- lib/apple_music_library/genre.rb
|
129
130
|
- lib/apple_music_library/library.rb
|
130
131
|
- lib/apple_music_library/playlist.rb
|
132
|
+
- lib/apple_music_library/playlist_folder.rb
|
131
133
|
- lib/apple_music_library/track.rb
|
132
134
|
- lib/apple_music_library/utils.rb
|
133
135
|
- lib/apple_music_library/version.rb
|
@@ -156,6 +158,6 @@ requirements: []
|
|
156
158
|
rubygems_version: 3.3.3
|
157
159
|
signing_key:
|
158
160
|
specification_version: 4
|
159
|
-
summary: Provides a
|
160
|
-
|
161
|
+
summary: Provides a Ruby interface to the information stored in an Apple Music (formerly
|
162
|
+
iTunes) Library xml file.
|
161
163
|
test_files: []
|