kagu 2.0.3 → 3.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 +4 -5
- data/lib/kagu/finder.rb +2 -6
- data/lib/kagu/library.rb +3 -18
- data/lib/kagu/playlist.rb +7 -11
- data/lib/kagu/playlists.rb +26 -41
- data/lib/kagu/swift_helper.rb +28 -0
- data/lib/kagu/track.rb +14 -56
- data/lib/kagu/tracks.rb +33 -19
- data/lib/kagu.rb +4 -1
- metadata +11 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 525d281da8b729c56214956d8fe81f699b105331c15e86976f65ffc983a0b2ea
|
4
|
+
data.tar.gz: 9a5200a627a5a6224f0f1d2a6972f9262515a1957ca33e60eebdac20be4303a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d54df53f2489cd5d5f6f734c994c89f03ee0fe5c8834547272f8cda4d5b206f6266b9a7474a72be5f734eeae9d0095969762cb5d042b1f600946de9260628670
|
7
|
+
data.tar.gz: 928913d1a8454a838ba48fc1c8bfecc992057276de00d22b904864859f66c70db3bf1bf5f2e1028600bacb21e18c5c21f850a7e18efd75fc7f52db41f7260706
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.0.0
|
data/kagu.gemspec
CHANGED
@@ -15,11 +15,10 @@ Gem::Specification.new do |s|
|
|
15
15
|
|
16
16
|
s.required_ruby_version = '>= 2.0.0'
|
17
17
|
|
18
|
-
s.add_dependency 'activesupport', '>= 4.1.0', '<
|
18
|
+
s.add_dependency 'activesupport', '>= 4.1.0', '< 7.0.0'
|
19
19
|
s.add_dependency 'applescript', '>= 1.0', '< 2.0'
|
20
|
-
s.add_dependency 'htmlentities', '>= 4.3.0', '< 4.4.0'
|
21
20
|
|
22
|
-
s.add_development_dependency 'byebug', '>= 3.2.0', '<
|
23
|
-
s.add_development_dependency 'rake', '>= 10.3.0', '<
|
24
|
-
s.add_development_dependency 'rspec', '>= 3.1.0', '< 3.
|
21
|
+
s.add_development_dependency 'byebug', '>= 3.2.0', '< 12.0.0'
|
22
|
+
s.add_development_dependency 'rake', '>= 10.3.0', '< 14.0.0'
|
23
|
+
s.add_development_dependency 'rspec', '>= 3.1.0', '< 3.10.0'
|
25
24
|
end
|
data/lib/kagu/finder.rb
CHANGED
@@ -4,8 +4,6 @@ module Kagu
|
|
4
4
|
|
5
5
|
MANDATORY_ATTRIBUTES = []
|
6
6
|
|
7
|
-
attr_reader :library
|
8
|
-
|
9
7
|
delegate :replace, :transliterate, to: 'self.class'
|
10
8
|
|
11
9
|
def self.replace(value, replacements = {})
|
@@ -20,9 +18,7 @@ module Kagu
|
|
20
18
|
ActiveSupport::Inflector.transliterate(value.to_s).squish.downcase.presence
|
21
19
|
end
|
22
20
|
|
23
|
-
def initialize(
|
24
|
-
raise ArgumentError.new("#{self.class}#library must be a library, #{library.inspect} given") unless library.is_a?(Library)
|
25
|
-
@library = library
|
21
|
+
def initialize(options = {})
|
26
22
|
reload(options)
|
27
23
|
end
|
28
24
|
|
@@ -115,7 +111,7 @@ module Kagu
|
|
115
111
|
|
116
112
|
def tracks
|
117
113
|
return @tracks if @tracks
|
118
|
-
(@tracks =
|
114
|
+
(@tracks = Tracks.new.to_a).tap do |tracks|
|
119
115
|
Kagu.logger.debug('Kagu') { "Loaded #{tracks.size} track(s) from library" }
|
120
116
|
end
|
121
117
|
end
|
data/lib/kagu/library.rb
CHANGED
@@ -2,31 +2,16 @@ module Kagu
|
|
2
2
|
|
3
3
|
class Library
|
4
4
|
|
5
|
-
PATH = File.expand_path("#{ENV['HOME']}/Music/iTunes/iTunes Music Library.xml")
|
6
|
-
|
7
|
-
attr_reader :path
|
8
|
-
|
9
|
-
def initialize(path = PATH)
|
10
|
-
self.path = path
|
11
|
-
end
|
12
|
-
|
13
5
|
def finder(options = {})
|
14
|
-
Finder.new(
|
6
|
+
Finder.new(options)
|
15
7
|
end
|
16
8
|
|
17
9
|
def playlists
|
18
|
-
Playlists.new
|
10
|
+
Playlists.new
|
19
11
|
end
|
20
12
|
|
21
13
|
def tracks
|
22
|
-
Tracks.new
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def path=(path)
|
28
|
-
raise Error.new("No such file: #{path.inspect}") unless File.file?(path)
|
29
|
-
@path = path
|
14
|
+
Tracks.new
|
30
15
|
end
|
31
16
|
|
32
17
|
end
|
data/lib/kagu/playlist.rb
CHANGED
@@ -28,15 +28,16 @@ module Kagu
|
|
28
28
|
private
|
29
29
|
|
30
30
|
def add_tracks
|
31
|
+
return if tracks.empty?
|
31
32
|
Kagu.logger.info('Kagu') { "Adding #{tracks.size} track(s) to playlist #{name.inspect}" }
|
32
|
-
|
33
|
+
Dir.mktmpdir do |directory|
|
34
|
+
path = "#{directory}/#{name}.m3u"
|
35
|
+
File.open(path, 'w') do |io|
|
36
|
+
tracks.each { |track| io << "file://#{URI.escape(track.path.to_s)}\n" }
|
37
|
+
end
|
33
38
|
AppleScript.execute(%Q{
|
34
39
|
tell application #{Kagu::OSX_APP_NAME.inspect}
|
35
|
-
|
36
|
-
set idsToAdd to {#{ids.join(',')}}
|
37
|
-
repeat with idToAdd in idsToAdd
|
38
|
-
duplicate (tracks of library playlist 1 whose database ID is idToAdd) to playlistToPush
|
39
|
-
end repeat
|
40
|
+
open #{path.inspect}
|
40
41
|
end tell
|
41
42
|
})
|
42
43
|
end
|
@@ -79,11 +80,6 @@ module Kagu
|
|
79
80
|
@tracks = [values].flatten.select { |value| value.is_a?(Track) }
|
80
81
|
end
|
81
82
|
|
82
|
-
def xml_name=(value)
|
83
|
-
@@html_entities ||= HTMLEntities.new
|
84
|
-
self.name = @@html_entities.decode(value)
|
85
|
-
end
|
86
|
-
|
87
83
|
end
|
88
84
|
|
89
85
|
end
|
data/lib/kagu/playlists.rb
CHANGED
@@ -4,13 +4,6 @@ module Kagu
|
|
4
4
|
|
5
5
|
include Enumerable
|
6
6
|
|
7
|
-
attr_reader :library
|
8
|
-
|
9
|
-
def initialize(library)
|
10
|
-
raise ArgumentError.new("#{self.class}#library must be a library, #{library.inspect} given") unless library.is_a?(Library)
|
11
|
-
@library = library
|
12
|
-
end
|
13
|
-
|
14
7
|
def build(attributes = {})
|
15
8
|
Playlist.new(attributes)
|
16
9
|
end
|
@@ -21,42 +14,34 @@ module Kagu
|
|
21
14
|
|
22
15
|
def each(&block)
|
23
16
|
return unless block_given?
|
17
|
+
Kagu.logger.debug('Kagu') { 'Loading library playlists' }
|
24
18
|
tracks = {}.tap do |tracks|
|
25
|
-
|
19
|
+
Tracks.new.each { |track| tracks[track.id] = track }
|
26
20
|
end
|
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
|
-
if name == 'Name'
|
52
|
-
if skip_next
|
53
|
-
skip_next = false
|
54
|
-
else
|
55
|
-
playlist_name = value
|
56
|
-
end
|
57
|
-
elsif name == 'Track ID'
|
58
|
-
playlist_tracks << tracks[value.to_i]
|
59
|
-
end
|
21
|
+
playlist_name = nil
|
22
|
+
playlist_tracks = []
|
23
|
+
SwiftHelper.execute(%Q{
|
24
|
+
import iTunesLibrary
|
25
|
+
|
26
|
+
let library = try! ITLibrary(apiVersion: "1")
|
27
|
+
for playlist in library.allPlaylists.filter({ !$0.isMaster }) {
|
28
|
+
print("BEGIN_PLAYLIST")
|
29
|
+
print(playlist.name)
|
30
|
+
for track in playlist.items.filter({ $0.mediaKind == ITLibMediaItemMediaKind.kindSong }) {
|
31
|
+
print(String(format: "%02X", track.persistentID.intValue))
|
32
|
+
}
|
33
|
+
print("END_PLAYLIST")
|
34
|
+
}
|
35
|
+
}) do |line|
|
36
|
+
if line == 'BEGIN_PLAYLIST'
|
37
|
+
playlist_name = nil
|
38
|
+
playlist_tracks = []
|
39
|
+
elsif line == 'END_PLAYLIST'
|
40
|
+
yield(Playlist.new(name: playlist_name, tracks: playlist_tracks)) if playlist_name.present?
|
41
|
+
elsif playlist_name.nil?
|
42
|
+
playlist_name = line
|
43
|
+
else
|
44
|
+
playlist_tracks << tracks[line]
|
60
45
|
end
|
61
46
|
end
|
62
47
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Kagu
|
2
|
+
|
3
|
+
module SwiftHelper
|
4
|
+
|
5
|
+
def self.execute(code, &block)
|
6
|
+
tempfile = Tempfile.new
|
7
|
+
begin
|
8
|
+
tempfile << code
|
9
|
+
ensure
|
10
|
+
tempfile.close
|
11
|
+
end
|
12
|
+
begin
|
13
|
+
stdout, stderr, result = Open3.capture3("swift #{tempfile.path.inspect}")
|
14
|
+
raise(stderr.presence || "Swift command returned with code: #{result.exitstatus}") unless result.success?
|
15
|
+
if block_given?
|
16
|
+
stdout.lines.each { |line| yield(line.chomp) }
|
17
|
+
nil
|
18
|
+
else
|
19
|
+
stdout
|
20
|
+
end
|
21
|
+
ensure
|
22
|
+
tempfile.unlink
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/lib/kagu/track.rb
CHANGED
@@ -9,10 +9,6 @@ module Kagu
|
|
9
9
|
|
10
10
|
attr_reader :added_at, :album, :artist, :bpm, :genre, :id, :length, :path, :title, :year
|
11
11
|
|
12
|
-
def initialize(attributes = {})
|
13
|
-
super
|
14
|
-
end
|
15
|
-
|
16
12
|
def <=>(other)
|
17
13
|
return nil unless other.is_a?(self.class)
|
18
14
|
length <=> other.length
|
@@ -27,7 +23,7 @@ module Kagu
|
|
27
23
|
end
|
28
24
|
|
29
25
|
def exists?
|
30
|
-
|
26
|
+
path.file?
|
31
27
|
end
|
32
28
|
|
33
29
|
def hash
|
@@ -35,7 +31,8 @@ module Kagu
|
|
35
31
|
end
|
36
32
|
|
37
33
|
def relative_path(directory)
|
38
|
-
directory
|
34
|
+
directory = directory.to_s
|
35
|
+
directory.present? ? Pathname.new(path.to_s.gsub(/\A#{Regexp.escape(directory)}\//, '')) : path
|
39
36
|
end
|
40
37
|
|
41
38
|
def to_s
|
@@ -45,6 +42,11 @@ module Kagu
|
|
45
42
|
private
|
46
43
|
|
47
44
|
def added_at=(value)
|
45
|
+
if value.is_a?(String)
|
46
|
+
value = Time.parse(value)
|
47
|
+
elsif value.is_a?(Integer)
|
48
|
+
value = Time.at(value)
|
49
|
+
end
|
48
50
|
@added_at = value.is_a?(Time) ? value.utc : nil
|
49
51
|
end
|
50
52
|
|
@@ -64,13 +66,8 @@ module Kagu
|
|
64
66
|
@genre = value.to_s.squish.presence
|
65
67
|
end
|
66
68
|
|
67
|
-
def html_entities_decode(value)
|
68
|
-
@@html_entities ||= HTMLEntities.new
|
69
|
-
@@html_entities.decode(value.to_s)
|
70
|
-
end
|
71
|
-
|
72
69
|
def id=(value)
|
73
|
-
@id = value.to_s
|
70
|
+
@id = value.to_s.presence
|
74
71
|
end
|
75
72
|
|
76
73
|
def length=(value)
|
@@ -78,8 +75,11 @@ module Kagu
|
|
78
75
|
end
|
79
76
|
|
80
77
|
def path=(value)
|
81
|
-
|
82
|
-
|
78
|
+
value = value.to_s.presence
|
79
|
+
value = URI.unescape(URI.parse(value).path) if value.is_a?(String) && value.starts_with?('file://')
|
80
|
+
value = value.encode('UTF-8', 'UTF-8-MAC') if Kagu::IS_MAC_OS
|
81
|
+
@path = Pathname.new(value)
|
82
|
+
raise Error.new("No such file: #{path.to_s.inspect}") if path.exist? && !exists?
|
83
83
|
Kagu.logger.error('Kagu') { "No such track: #{path.inspect}" } unless exists?
|
84
84
|
end
|
85
85
|
|
@@ -87,48 +87,6 @@ module Kagu
|
|
87
87
|
@title = value.to_s.squish.presence
|
88
88
|
end
|
89
89
|
|
90
|
-
def xml_album=(value)
|
91
|
-
self.album = html_entities_decode(value)
|
92
|
-
end
|
93
|
-
|
94
|
-
def xml_artist=(value)
|
95
|
-
self.artist = html_entities_decode(value)
|
96
|
-
end
|
97
|
-
|
98
|
-
def xml_bpm=(value)
|
99
|
-
self.bpm = value
|
100
|
-
end
|
101
|
-
|
102
|
-
def xml_date_added=(value)
|
103
|
-
self.added_at = value.present? ? Time.parse(value.to_s) : nil
|
104
|
-
end
|
105
|
-
|
106
|
-
def xml_genre=(value)
|
107
|
-
self.genre = html_entities_decode(value)
|
108
|
-
end
|
109
|
-
|
110
|
-
def xml_location=(value)
|
111
|
-
path = CGI.unescape(html_entities_decode(value).gsub('+', '%2B')).gsub(/\Afile:\/\/(localhost)?/, '')
|
112
|
-
path = path.encode('UTF-8', 'UTF-8-MAC') if Kagu::IS_MAC_OS
|
113
|
-
self.path = path
|
114
|
-
end
|
115
|
-
|
116
|
-
def xml_name=(value)
|
117
|
-
self.title = html_entities_decode(value)
|
118
|
-
end
|
119
|
-
|
120
|
-
def xml_total_time=(value)
|
121
|
-
self.length = value.to_s =~ /\A[0-9]+\z/ ? (value.to_i / 1000.0).round : nil
|
122
|
-
end
|
123
|
-
|
124
|
-
def xml_track_id=(value)
|
125
|
-
self.id = value
|
126
|
-
end
|
127
|
-
|
128
|
-
def xml_year=(value)
|
129
|
-
self.year = value
|
130
|
-
end
|
131
|
-
|
132
90
|
def year=(value)
|
133
91
|
@year = value.to_s =~ /\A\d{,4}\z/ ? value.to_i : nil
|
134
92
|
end
|
data/lib/kagu/tracks.rb
CHANGED
@@ -6,28 +6,42 @@ module Kagu
|
|
6
6
|
|
7
7
|
EXTENSIONS = %w(.aac .flac .mp3 .wav).freeze
|
8
8
|
|
9
|
-
attr_reader :library
|
10
|
-
|
11
|
-
def initialize(library)
|
12
|
-
raise ArgumentError.new("#{self.class}#library must be a library, #{library.inspect} given") unless library.is_a?(Library)
|
13
|
-
@library = library
|
14
|
-
end
|
15
|
-
|
16
9
|
def each(&block)
|
17
10
|
return unless block_given?
|
18
|
-
Kagu.logger.debug('Kagu') {
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
Kagu.logger.debug('Kagu') { 'Loading library tracks' }
|
12
|
+
attributes = {}
|
13
|
+
SwiftHelper.execute(%Q{
|
14
|
+
import iTunesLibrary
|
15
|
+
|
16
|
+
func printObjectProperty<T: Encodable>(name: String, value: T?) {
|
17
|
+
let jsonEncoder = JSONEncoder()
|
18
|
+
let jsonData = try! jsonEncoder.encode(value)
|
19
|
+
let json = String(data: jsonData, encoding: String.Encoding.utf8)
|
20
|
+
print("\\(name)=\\(json!)")
|
21
|
+
}
|
22
|
+
|
23
|
+
let library = try! ITLibrary(apiVersion: "1")
|
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")
|
37
|
+
}
|
38
|
+
}) do |line|
|
39
|
+
if line == 'BEGIN_TRACK'
|
22
40
|
attributes = {}
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
value = match[3]
|
28
|
-
attributes[name] = value
|
29
|
-
end while (line = file.readline.strip) != '</dict>'
|
30
|
-
yield(Track.new(attributes)) if attributes['xml_track_type'] == 'File' && attributes['xml_podcast'].blank? && EXTENSIONS.include?(File.extname(attributes['xml_location'].try(:downcase)))
|
41
|
+
elsif line == 'END_TRACK'
|
42
|
+
yield(Track.new(attributes))
|
43
|
+
elsif match = /(^\w+)=(.*)/.match(line)
|
44
|
+
attributes[match[1]] = JSON.parse(match[2])
|
31
45
|
end
|
32
46
|
end
|
33
47
|
end
|
data/lib/kagu.rb
CHANGED
@@ -2,8 +2,10 @@ require 'active_support'
|
|
2
2
|
require 'active_support/core_ext'
|
3
3
|
require 'applescript'
|
4
4
|
require 'byebug' if ENV['DEBUGGER']
|
5
|
-
require 'htmlentities'
|
6
5
|
require 'logger'
|
6
|
+
require 'open3'
|
7
|
+
require 'pathname'
|
8
|
+
require 'tempfile'
|
7
9
|
|
8
10
|
lib_path = "#{__dir__}/kagu"
|
9
11
|
|
@@ -29,5 +31,6 @@ require "#{lib_path}/finder"
|
|
29
31
|
require "#{lib_path}/library"
|
30
32
|
require "#{lib_path}/playlist"
|
31
33
|
require "#{lib_path}/playlists"
|
34
|
+
require "#{lib_path}/swift_helper"
|
32
35
|
require "#{lib_path}/track"
|
33
36
|
require "#{lib_path}/tracks"
|
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: 3.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: 2019-
|
11
|
+
date: 2019-12-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: 4.1.0
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
22
|
+
version: 7.0.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: 4.1.0
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
32
|
+
version: 7.0.0
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: applescript
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,26 +50,6 @@ dependencies:
|
|
50
50
|
- - "<"
|
51
51
|
- !ruby/object:Gem::Version
|
52
52
|
version: '2.0'
|
53
|
-
- !ruby/object:Gem::Dependency
|
54
|
-
name: htmlentities
|
55
|
-
requirement: !ruby/object:Gem::Requirement
|
56
|
-
requirements:
|
57
|
-
- - ">="
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
version: 4.3.0
|
60
|
-
- - "<"
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: 4.4.0
|
63
|
-
type: :runtime
|
64
|
-
prerelease: false
|
65
|
-
version_requirements: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- - ">="
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: 4.3.0
|
70
|
-
- - "<"
|
71
|
-
- !ruby/object:Gem::Version
|
72
|
-
version: 4.4.0
|
73
53
|
- !ruby/object:Gem::Dependency
|
74
54
|
name: byebug
|
75
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -79,7 +59,7 @@ dependencies:
|
|
79
59
|
version: 3.2.0
|
80
60
|
- - "<"
|
81
61
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
62
|
+
version: 12.0.0
|
83
63
|
type: :development
|
84
64
|
prerelease: false
|
85
65
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -89,7 +69,7 @@ dependencies:
|
|
89
69
|
version: 3.2.0
|
90
70
|
- - "<"
|
91
71
|
- !ruby/object:Gem::Version
|
92
|
-
version:
|
72
|
+
version: 12.0.0
|
93
73
|
- !ruby/object:Gem::Dependency
|
94
74
|
name: rake
|
95
75
|
requirement: !ruby/object:Gem::Requirement
|
@@ -99,7 +79,7 @@ dependencies:
|
|
99
79
|
version: 10.3.0
|
100
80
|
- - "<"
|
101
81
|
- !ruby/object:Gem::Version
|
102
|
-
version:
|
82
|
+
version: 14.0.0
|
103
83
|
type: :development
|
104
84
|
prerelease: false
|
105
85
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -109,7 +89,7 @@ dependencies:
|
|
109
89
|
version: 10.3.0
|
110
90
|
- - "<"
|
111
91
|
- !ruby/object:Gem::Version
|
112
|
-
version:
|
92
|
+
version: 14.0.0
|
113
93
|
- !ruby/object:Gem::Dependency
|
114
94
|
name: rspec
|
115
95
|
requirement: !ruby/object:Gem::Requirement
|
@@ -119,7 +99,7 @@ dependencies:
|
|
119
99
|
version: 3.1.0
|
120
100
|
- - "<"
|
121
101
|
- !ruby/object:Gem::Version
|
122
|
-
version: 3.
|
102
|
+
version: 3.10.0
|
123
103
|
type: :development
|
124
104
|
prerelease: false
|
125
105
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -129,7 +109,7 @@ dependencies:
|
|
129
109
|
version: 3.1.0
|
130
110
|
- - "<"
|
131
111
|
- !ruby/object:Gem::Version
|
132
|
-
version: 3.
|
112
|
+
version: 3.10.0
|
133
113
|
description: API to manage macOS Music tracks and playlists
|
134
114
|
email: al@alweb.org
|
135
115
|
executables: []
|
@@ -147,6 +127,7 @@ files:
|
|
147
127
|
- lib/kagu/library.rb
|
148
128
|
- lib/kagu/playlist.rb
|
149
129
|
- lib/kagu/playlists.rb
|
130
|
+
- lib/kagu/swift_helper.rb
|
150
131
|
- lib/kagu/track.rb
|
151
132
|
- lib/kagu/tracks.rb
|
152
133
|
homepage: https://github.com/alexistoulotte/kagu
|