kagu 3.2.0 → 4.0.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/VERSION +1 -1
- data/kagu.gemspec +7 -4
- data/lib/kagu/finder.rb +5 -4
- data/lib/kagu/playlist.rb +8 -8
- data/lib/kagu/playlists.rb +8 -8
- data/lib/kagu/track.rb +5 -4
- data/lib/kagu/tracks.rb +18 -18
- data/lib/kagu.rb +1 -3
- metadata +68 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d1cedd40180e7fdaaafb0a589b9497904dc1fea117988356a1b9825720d906eb
|
4
|
+
data.tar.gz: 6bd45283ddd23b1151928c3d5fe01fa57591df612c90604a1994271500dcf380
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c58699f791c9f6451aa0e2c40b98bbd8cf7749655e27b96856ed73a5273e323948891025df00d6f84f510b079b4fab00ab629e54c7d4cb6ed3a1f3268438b53
|
7
|
+
data.tar.gz: cb1ceb390210ae2ce2408cd9c801dd9853aa8712767e178eebac86864bb2d670a4042c190be832b55714c9570b33993ac27a314ae404f107bbd8b53f61158320
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
4.0.0
|
data/kagu.gemspec
CHANGED
@@ -9,17 +9,20 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.description = 'API to manage macOS Music tracks and playlists'
|
10
10
|
s.license = 'MIT'
|
11
11
|
|
12
|
-
s.files =
|
13
|
-
s.executables =
|
12
|
+
s.files = %x(git ls-files | grep -vE '^(spec/|test/|\\.|Gemfile|Rakefile)').split("\n")
|
13
|
+
s.executables = %x(git ls-files -- bin/*).split("\n").map { |f| File.basename(f) }
|
14
14
|
s.require_paths = ['lib']
|
15
15
|
|
16
|
-
s.required_ruby_version = '>=
|
16
|
+
s.required_ruby_version = '>= 3.1.0'
|
17
17
|
|
18
|
-
s.add_dependency 'activesupport', '>=
|
18
|
+
s.add_dependency 'activesupport', '>= 7.0.0', '< 8.0.0'
|
19
19
|
s.add_dependency 'addressable', '>= 2.7.0', '< 3.0.0'
|
20
20
|
s.add_dependency 'applescript', '>= 1.0', '< 2.0'
|
21
21
|
|
22
22
|
s.add_development_dependency 'byebug', '>= 3.2.0', '< 12.0.0'
|
23
23
|
s.add_development_dependency 'rake', '>= 10.3.0', '< 14.0.0'
|
24
24
|
s.add_development_dependency 'rspec', '>= 3.1.0', '< 3.11.0'
|
25
|
+
s.add_development_dependency 'rubocop', '>= 1.25.0', '< 2.0.0'
|
26
|
+
s.add_development_dependency 'rubocop-rake', '>= 0.6.0', '< 1.0.0'
|
27
|
+
s.add_development_dependency 'rubocop-rspec', '>= 2.8.0', '< 3.0.0'
|
25
28
|
end
|
data/lib/kagu/finder.rb
CHANGED
@@ -2,7 +2,7 @@ module Kagu
|
|
2
2
|
|
3
3
|
class Finder
|
4
4
|
|
5
|
-
MANDATORY_ATTRIBUTES = []
|
5
|
+
MANDATORY_ATTRIBUTES = [].freeze
|
6
6
|
|
7
7
|
delegate :replace, :transliterate, to: 'self.class'
|
8
8
|
|
@@ -29,7 +29,7 @@ module Kagu
|
|
29
29
|
tracks_digests.each_with_index do |hash, digests_index|
|
30
30
|
digests(attributes).each_with_index do |digest, digest_index|
|
31
31
|
tracks = hash[digest].presence || next
|
32
|
-
tracks = tracks.
|
32
|
+
tracks = tracks.reject { |track| matches.any? { |match| match.try(:include?, track) } }
|
33
33
|
next if tracks.empty?
|
34
34
|
index = [digests_index, digest_index].max
|
35
35
|
matches[index] ||= []
|
@@ -83,10 +83,11 @@ module Kagu
|
|
83
83
|
|
84
84
|
def ignored=(values)
|
85
85
|
@ignored = [values].flatten.map do |value|
|
86
|
-
|
86
|
+
case value
|
87
|
+
when Hash
|
87
88
|
value = value.stringify_keys
|
88
89
|
value = "#{value['artist']} #{value['title']}"
|
89
|
-
|
90
|
+
when Track
|
90
91
|
value = "#{value.artist} #{value.title}"
|
91
92
|
else
|
92
93
|
value = value.to_s
|
data/lib/kagu/playlist.rb
CHANGED
@@ -2,12 +2,12 @@ module Kagu
|
|
2
2
|
|
3
3
|
class Playlist
|
4
4
|
|
5
|
-
MANDATORY_ATTRIBUTES = %w(name)
|
5
|
+
MANDATORY_ATTRIBUTES = %w(name).freeze
|
6
6
|
|
7
7
|
include AttributesInitializer
|
8
8
|
include Enumerable
|
9
9
|
|
10
|
-
attr_reader :name
|
10
|
+
attr_reader :name
|
11
11
|
|
12
12
|
delegate :each, to: :tracks
|
13
13
|
|
@@ -31,7 +31,7 @@ module Kagu
|
|
31
31
|
return if tracks.empty?
|
32
32
|
Kagu.logger.info('Kagu') { "Adding #{tracks.size} track(s) to playlist #{name.inspect}" }
|
33
33
|
tracks.map(&:id).each_slice(500) do |ids|
|
34
|
-
AppleScript.execute(
|
34
|
+
AppleScript.execute("
|
35
35
|
tell application #{Kagu::OSX_APP_NAME.inspect}
|
36
36
|
set playlistToPush to user playlist #{name.inspect}
|
37
37
|
set idsToAdd to {#{ids.map(&:inspect).join(',')}}
|
@@ -39,7 +39,7 @@ module Kagu
|
|
39
39
|
duplicate (tracks of library playlist 1 whose persistent ID is idToAdd) to playlistToPush
|
40
40
|
end repeat
|
41
41
|
end tell
|
42
|
-
|
42
|
+
")
|
43
43
|
end
|
44
44
|
true
|
45
45
|
rescue => e
|
@@ -48,11 +48,11 @@ module Kagu
|
|
48
48
|
|
49
49
|
def clear
|
50
50
|
Kagu.logger.info('Kagu') { "Removing all tracks from playlist #{name.inspect}" }
|
51
|
-
AppleScript.execute(
|
51
|
+
AppleScript.execute("
|
52
52
|
tell application #{Kagu::OSX_APP_NAME.inspect}
|
53
53
|
delete tracks of playlist #{name.inspect}
|
54
54
|
end tell
|
55
|
-
|
55
|
+
")
|
56
56
|
true
|
57
57
|
rescue => e
|
58
58
|
raise Error.new(e)
|
@@ -60,13 +60,13 @@ module Kagu
|
|
60
60
|
|
61
61
|
def create
|
62
62
|
Kagu.logger.info('Kagu') { "Creating playlist #{name.inspect}" }
|
63
|
-
AppleScript.execute(
|
63
|
+
AppleScript.execute("
|
64
64
|
tell application #{Kagu::OSX_APP_NAME.inspect}
|
65
65
|
if not (exists user playlist #{name.inspect}) then
|
66
66
|
make new user playlist with properties { name: #{name.inspect} }
|
67
67
|
end if
|
68
68
|
end tell
|
69
|
-
|
69
|
+
")
|
70
70
|
true
|
71
71
|
rescue => e
|
72
72
|
raise Error.new(e)
|
data/lib/kagu/playlists.rb
CHANGED
@@ -12,27 +12,27 @@ module Kagu
|
|
12
12
|
build(attributes).tap(&:save)
|
13
13
|
end
|
14
14
|
|
15
|
-
def each
|
15
|
+
def each
|
16
16
|
return unless block_given?
|
17
17
|
Kagu.logger.debug('Kagu') { 'Loading library playlists' }
|
18
|
-
tracks = {}.tap do |
|
19
|
-
Tracks.new.each { |track|
|
18
|
+
tracks = {}.tap do |items|
|
19
|
+
Tracks.new.each { |track| items[track.id] = track }
|
20
20
|
end
|
21
21
|
playlist_name = nil
|
22
22
|
playlist_tracks = []
|
23
|
-
SwiftHelper.execute(
|
23
|
+
SwiftHelper.execute("
|
24
24
|
import iTunesLibrary
|
25
25
|
|
26
|
-
let library = try! ITLibrary(apiVersion: "1")
|
26
|
+
let library = try! ITLibrary(apiVersion: \"1\")
|
27
27
|
for playlist in library.allPlaylists.filter({ !$0.isMaster }) {
|
28
|
-
print("BEGIN_PLAYLIST")
|
28
|
+
print(\"BEGIN_PLAYLIST\")
|
29
29
|
print(playlist.name)
|
30
30
|
for track in playlist.items.filter({ $0.mediaKind == ITLibMediaItemMediaKind.kindSong }) {
|
31
31
|
print(String(track.persistentID.uint64Value, radix: 16).uppercased())
|
32
32
|
}
|
33
|
-
print("END_PLAYLIST")
|
33
|
+
print(\"END_PLAYLIST\")
|
34
34
|
}
|
35
|
-
|
35
|
+
").each do |line|
|
36
36
|
if line == 'BEGIN_PLAYLIST'
|
37
37
|
playlist_name = nil
|
38
38
|
playlist_tracks = []
|
data/lib/kagu/track.rb
CHANGED
@@ -5,7 +5,7 @@ module Kagu
|
|
5
5
|
include AttributesInitializer
|
6
6
|
include Comparable
|
7
7
|
|
8
|
-
MANDATORY_ATTRIBUTES = %w(added_at id length)
|
8
|
+
MANDATORY_ATTRIBUTES = %w(added_at id length).freeze
|
9
9
|
|
10
10
|
attr_reader :added_at, :album, :artist, :bpm, :genre, :id, :length, :path, :title, :year
|
11
11
|
|
@@ -37,9 +37,10 @@ module Kagu
|
|
37
37
|
private
|
38
38
|
|
39
39
|
def added_at=(value)
|
40
|
-
|
40
|
+
case value
|
41
|
+
when String
|
41
42
|
value = Time.parse(value)
|
42
|
-
|
43
|
+
when Integer
|
43
44
|
value = Time.at(value)
|
44
45
|
end
|
45
46
|
@added_at = value.is_a?(Time) ? value.utc : nil
|
@@ -55,7 +56,7 @@ module Kagu
|
|
55
56
|
|
56
57
|
def bpm=(value)
|
57
58
|
value = value.to_s =~ /\A[0-9]+\z/ ? value.to_i : nil
|
58
|
-
@bpm =
|
59
|
+
@bpm = value && value > 0 ? value : nil
|
59
60
|
end
|
60
61
|
|
61
62
|
def genre=(value)
|
data/lib/kagu/tracks.rb
CHANGED
@@ -6,41 +6,41 @@ module Kagu
|
|
6
6
|
|
7
7
|
EXTENSIONS = %w(.aac .flac .mp3 .wav).freeze
|
8
8
|
|
9
|
-
def each
|
9
|
+
def each
|
10
10
|
return unless block_given?
|
11
11
|
Kagu.logger.debug('Kagu') { 'Loading library tracks' }
|
12
12
|
attributes = {}
|
13
|
-
SwiftHelper.execute(
|
13
|
+
SwiftHelper.execute("
|
14
14
|
import iTunesLibrary
|
15
15
|
|
16
16
|
func printObjectProperty<T: Encodable>(name: String, value: T?) {
|
17
17
|
let jsonEncoder = JSONEncoder()
|
18
18
|
let jsonData = try! jsonEncoder.encode(value)
|
19
19
|
let json = String(data: jsonData, encoding: String.Encoding.utf8)
|
20
|
-
print("\\(name)=\\(json!)")
|
20
|
+
print(\"\\(name)=\\(json!)\")
|
21
21
|
}
|
22
22
|
|
23
|
-
let library = try! ITLibrary(apiVersion: "1")
|
23
|
+
let library = try! ITLibrary(apiVersion: \"1\")
|
24
24
|
for track in library.allMediaItems.filter({ $0.mediaKind == ITLibMediaItemMediaKind.kindSong }) {
|
25
|
-
print("BEGIN_TRACK")
|
26
|
-
printObjectProperty(name: "added_at", value: track.addedDate!.timeIntervalSince1970)
|
27
|
-
printObjectProperty(name: "album", value: track.album.title)
|
28
|
-
printObjectProperty(name: "artist", value: track.artist!.name)
|
29
|
-
printObjectProperty(name: "bpm", value: track.beatsPerMinute)
|
30
|
-
printObjectProperty(name: "genre", value: track.genre)
|
31
|
-
printObjectProperty(name: "id", value: String(track.persistentID.uint64Value, radix: 16).uppercased())
|
32
|
-
printObjectProperty(name: "length", value: track.totalTime)
|
33
|
-
printObjectProperty(name: "path", value: track.location)
|
34
|
-
printObjectProperty(name: "title", value: track.title)
|
35
|
-
printObjectProperty(name: "year", value: track.year)
|
36
|
-
print("END_TRACK")
|
25
|
+
print(\"BEGIN_TRACK\")
|
26
|
+
printObjectProperty(name: \"added_at\", value: track.addedDate!.timeIntervalSince1970)
|
27
|
+
printObjectProperty(name: \"album\", value: track.album.title)
|
28
|
+
printObjectProperty(name: \"artist\", value: track.artist!.name)
|
29
|
+
printObjectProperty(name: \"bpm\", value: track.beatsPerMinute)
|
30
|
+
printObjectProperty(name: \"genre\", value: track.genre)
|
31
|
+
printObjectProperty(name: \"id\", value: String(track.persistentID.uint64Value, radix: 16).uppercased())
|
32
|
+
printObjectProperty(name: \"length\", value: track.totalTime)
|
33
|
+
printObjectProperty(name: \"path\", value: track.location)
|
34
|
+
printObjectProperty(name: \"title\", value: track.title)
|
35
|
+
printObjectProperty(name: \"year\", value: track.year)
|
36
|
+
print(\"END_TRACK\")
|
37
37
|
}
|
38
|
-
|
38
|
+
").each do |line|
|
39
39
|
if line == 'BEGIN_TRACK'
|
40
40
|
attributes = {}
|
41
41
|
elsif line == 'END_TRACK'
|
42
42
|
yield(Track.new(attributes))
|
43
|
-
elsif match = /(^\w+)=(.*)/.match(line)
|
43
|
+
elsif (match = /(^\w+)=(.*)/.match(line))
|
44
44
|
attributes[match[1]] = JSON.parse(match[2])
|
45
45
|
end
|
46
46
|
end
|
data/lib/kagu.rb
CHANGED
@@ -15,9 +15,7 @@ module Kagu
|
|
15
15
|
IS_MAC_OS = RUBY_PLATFORM =~ /darwin/
|
16
16
|
OSX_APP_NAME = begin
|
17
17
|
if IS_MAC_OS
|
18
|
-
|
19
|
-
else
|
20
|
-
nil
|
18
|
+
%x(sw_vers -productVersion).chomp.to_f >= 10.15 ? 'Music' : 'iTunes'
|
21
19
|
end
|
22
20
|
end
|
23
21
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kagu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexis Toulotte
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,20 +16,20 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 7.0.0
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
22
|
+
version: 8.0.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
29
|
+
version: 7.0.0
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
32
|
+
version: 8.0.0
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: addressable
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -130,6 +130,66 @@ dependencies:
|
|
130
130
|
- - "<"
|
131
131
|
- !ruby/object:Gem::Version
|
132
132
|
version: 3.11.0
|
133
|
+
- !ruby/object:Gem::Dependency
|
134
|
+
name: rubocop
|
135
|
+
requirement: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: 1.25.0
|
140
|
+
- - "<"
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: 2.0.0
|
143
|
+
type: :development
|
144
|
+
prerelease: false
|
145
|
+
version_requirements: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 1.25.0
|
150
|
+
- - "<"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 2.0.0
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rubocop-rake
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 0.6.0
|
160
|
+
- - "<"
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: 1.0.0
|
163
|
+
type: :development
|
164
|
+
prerelease: false
|
165
|
+
version_requirements: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - ">="
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: 0.6.0
|
170
|
+
- - "<"
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: 1.0.0
|
173
|
+
- !ruby/object:Gem::Dependency
|
174
|
+
name: rubocop-rspec
|
175
|
+
requirement: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - ">="
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: 2.8.0
|
180
|
+
- - "<"
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: 3.0.0
|
183
|
+
type: :development
|
184
|
+
prerelease: false
|
185
|
+
version_requirements: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: 2.8.0
|
190
|
+
- - "<"
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: 3.0.0
|
133
193
|
description: API to manage macOS Music tracks and playlists
|
134
194
|
email: al@alweb.org
|
135
195
|
executables: []
|
@@ -162,14 +222,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
162
222
|
requirements:
|
163
223
|
- - ">="
|
164
224
|
- !ruby/object:Gem::Version
|
165
|
-
version:
|
225
|
+
version: 3.1.0
|
166
226
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
227
|
requirements:
|
168
228
|
- - ">="
|
169
229
|
- !ruby/object:Gem::Version
|
170
230
|
version: '0'
|
171
231
|
requirements: []
|
172
|
-
rubygems_version: 3.
|
232
|
+
rubygems_version: 3.3.3
|
173
233
|
signing_key:
|
174
234
|
specification_version: 4
|
175
235
|
summary: API for macOS Music
|