unitf-tag 0.1.16 → 0.1.25
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/.gitignore +2 -0
- data/.rubocop.yml +16 -1
- data/.vscode/tasks.json +1 -1
- data/CHANGELOG.md +3 -4
- data/bin/test.rb +16 -1
- data/exe/tag +15 -50
- data/lib/unitf/tag/file.rb +114 -42
- data/lib/unitf/tag/fileset.rb +7 -2
- data/lib/unitf/tag/flac.rb +6 -5
- data/lib/unitf/tag/helpers.rb +14 -0
- data/lib/unitf/tag/mp3.rb +7 -6
- data/lib/unitf/tag/version.rb +1 -1
- data/lib/unitf/tag.rb +23 -55
- data/unitf-tag.gemspec +17 -16
- metadata +5 -9
- data/bin/console +0 -15
- data/bin/setup +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7289107ae3745345d0485a0cd9dde05aec68cfe8a22ce366a45fe047467ad55f
|
4
|
+
data.tar.gz: 11f751c7a07a90b39589a03088589c48514734819e9318de36a4371bc7263049
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e51cf3871b7fbe25c2f9adcc23389430cb02d1551cd61efcad6817209dc18723aa8f17282554e1af752db6af2e2adfdd043eabb4d54d3f1ced29651c0863146f
|
7
|
+
data.tar.gz: e397e4fb24ed3e2cce546c08a1d47b07dec9b1adaefd9df3b0f1ff7163591eb2485a7065603c2316169da240ab161edf5fe7e330f872b0de11d7bc6febb9704a
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
AllCops:
|
2
|
+
NewCops: enable
|
3
|
+
|
1
4
|
Layout/EmptyLineAfterGuardClause:
|
2
5
|
Enabled: false
|
3
6
|
|
@@ -10,5 +13,17 @@ Style/FrozenStringLiteralComment:
|
|
10
13
|
Metrics/MethodLength:
|
11
14
|
Enabled: false
|
12
15
|
|
13
|
-
Metrics/AbcSize:
|
16
|
+
Metrics/AbcSize:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Metrics/ClassLength:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Style/FormatStringToken:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
Style/FormatString:
|
14
26
|
Enabled: false
|
27
|
+
|
28
|
+
Metrics/BlockLength:
|
29
|
+
Enabled: false
|
data/.vscode/tasks.json
CHANGED
data/CHANGELOG.md
CHANGED
data/bin/test.rb
CHANGED
@@ -4,8 +4,23 @@ require 'unitf/tag'
|
|
4
4
|
|
5
5
|
UnitF::Log.to_console
|
6
6
|
|
7
|
-
UnitF::Tag.update('/
|
7
|
+
UnitF::Tag.update('test-data/foo.mp3') do |file|
|
8
8
|
file.tag.artist = 'bar123'
|
9
9
|
file.tag.year = 1972
|
10
|
+
file.tag.album = 'This is the album'
|
11
|
+
file.tag.title = 'This is the title'
|
12
|
+
file.tag.track = 99
|
10
13
|
file.auto_cover!
|
11
14
|
end
|
15
|
+
|
16
|
+
file = UnitF::Tag::File.new('test-data/bar.mp3')
|
17
|
+
# file.tag
|
18
|
+
|
19
|
+
file.update do |f|
|
20
|
+
f.tag.title = 'Hello world2!'
|
21
|
+
f.tag.track = 100
|
22
|
+
end
|
23
|
+
|
24
|
+
file.open do |f|
|
25
|
+
f.tag.title = 'Hello world9!'
|
26
|
+
end
|
data/exe/tag
CHANGED
@@ -10,10 +10,10 @@ require 'unitf/logging'
|
|
10
10
|
UnitF::Log.to_console
|
11
11
|
|
12
12
|
actions = []
|
13
|
-
files = []
|
14
13
|
opt = {}
|
14
|
+
properties = {}
|
15
15
|
|
16
|
-
no_args = ARGV.
|
16
|
+
no_args = ARGV.empty?
|
17
17
|
|
18
18
|
targets = OptionParser.new do |opts|
|
19
19
|
opts.on('-r', '--recursive', 'Auto Cover') do
|
@@ -38,7 +38,7 @@ targets = OptionParser.new do |opts|
|
|
38
38
|
|
39
39
|
opts.on('--cover COVER', 'Cover') do |arg|
|
40
40
|
actions << :cover
|
41
|
-
raise "Invalid cover file #{arg}" unless
|
41
|
+
raise "Invalid cover file #{arg}" unless File.exist?(arg) && arg.downcase.end_with?('.jpg')
|
42
42
|
opt[:cover] = arg
|
43
43
|
end
|
44
44
|
|
@@ -59,33 +59,27 @@ targets = OptionParser.new do |opts|
|
|
59
59
|
end
|
60
60
|
|
61
61
|
opts.on('--artist ARTIST', 'Artist') do |arg|
|
62
|
-
|
63
|
-
opt[:artist] = arg
|
62
|
+
properties[:artist] = arg
|
64
63
|
end
|
65
64
|
|
66
65
|
opts.on('--album ALBUM', 'Album') do |arg|
|
67
|
-
|
68
|
-
opt[:album] = arg
|
66
|
+
properties[:album] = arg
|
69
67
|
end
|
70
68
|
|
71
69
|
opts.on('--title TITLE', 'Song Title') do |arg|
|
72
|
-
|
73
|
-
opt[:title] = arg
|
70
|
+
properties[:title] = arg
|
74
71
|
end
|
75
72
|
|
76
73
|
opts.on('--year YEAR', 'Song Year') do |arg|
|
77
|
-
|
78
|
-
opt[:year] = arg.to_i
|
74
|
+
properties[:year] = arg.to_i
|
79
75
|
end
|
80
76
|
|
81
77
|
opts.on('--genre GENRE', 'Genre') do |arg|
|
82
|
-
|
83
|
-
opt[:genre] = arg
|
78
|
+
properties[:genre] = arg
|
84
79
|
end
|
85
80
|
|
86
81
|
opts.on('--track TRACK', 'Song Track') do |arg|
|
87
|
-
|
88
|
-
opt[:track] = arg.to_i
|
82
|
+
properties[:track] = arg.to_i
|
89
83
|
end
|
90
84
|
end.parse!
|
91
85
|
|
@@ -93,58 +87,29 @@ targets = Dir.glob('*') if no_args
|
|
93
87
|
|
94
88
|
files = UnitF::Tag::FileSet.new(targets)
|
95
89
|
|
96
|
-
if files.
|
97
|
-
UnitF::Log.error('Cannot find any files to operate on')
|
98
|
-
end
|
90
|
+
UnitF::Log.error('Cannot find any files to operate on') if files.empty?
|
99
91
|
|
100
|
-
if actions.
|
92
|
+
if actions.empty? && properties.empty?
|
101
93
|
UnitF::Tag.list(files, format: opt[:format])
|
102
94
|
exit 0
|
103
95
|
end
|
104
96
|
|
105
97
|
files.each do |file|
|
106
98
|
UnitF::Log.info("Processing file: #{file}")
|
107
|
-
file.
|
99
|
+
file.update do |o|
|
100
|
+
o.properties!(properties) unless properties.empty?
|
101
|
+
|
108
102
|
actions.each do |action|
|
109
103
|
case action
|
110
104
|
when :cover
|
111
|
-
UnitF::Log.info("Cover #{opt[:cover]}")
|
112
105
|
o.cover!(opt[:cover])
|
113
106
|
when :delete_cover
|
114
|
-
UnitF::Log.info('Delete cover')
|
115
107
|
o.delete_cover!
|
116
108
|
when :auto_cover
|
117
|
-
|
118
|
-
UnitF::Log.info("Auto Cover #{file.cover_path}")
|
119
|
-
begin
|
120
|
-
o.auto_cover!
|
121
|
-
rescue => e
|
122
|
-
UnitF::Log.error("Failed to auto-cover file #{e}")
|
123
|
-
end
|
124
|
-
end
|
109
|
+
o.auto_cover!
|
125
110
|
when :auto_tag
|
126
|
-
UnitF::Log.info("Auto Tag #{file}")
|
127
111
|
o.auto_tag!
|
128
|
-
when :artist
|
129
|
-
UnitF::Log.info("Setting artist to #{opt[:artist]}")
|
130
|
-
o.tag.artist = opt[:artist]
|
131
|
-
when :album
|
132
|
-
UnitF::Log.info("Setting album to #{opt[:album]}")
|
133
|
-
o.tag.album = opt[:album]
|
134
|
-
when :title
|
135
|
-
UnitF::Log.info("Setting title to #{opt[:title]}")
|
136
|
-
o.tag.title = opt[:title]
|
137
|
-
when :genre
|
138
|
-
UnitF::Log.info("Setting genre to #{opt[:genre]}")
|
139
|
-
o.tag.genre = opt[:genre]
|
140
|
-
when :track
|
141
|
-
UnitF::Log.info("Setting track to #{opt[:track]}")
|
142
|
-
o.tag.track = opt[:track]
|
143
|
-
when :year
|
144
|
-
UnitF::Log.info("Setting year to #{opt[:year]}")
|
145
|
-
o.tag.year = opt[:year]
|
146
112
|
end
|
147
113
|
end
|
148
|
-
o.save || UnitF::Log.error("Unable to save changes to #{file}")
|
149
114
|
end
|
150
115
|
end
|
data/lib/unitf/tag/file.rb
CHANGED
@@ -12,7 +12,18 @@ module UnitF
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def tag
|
15
|
-
@file.
|
15
|
+
raise Error, "File is not open #{self.class.name}" if @file&.tag.nil?
|
16
|
+
|
17
|
+
@file&.tag
|
18
|
+
end
|
19
|
+
|
20
|
+
def save
|
21
|
+
@file&.save
|
22
|
+
end
|
23
|
+
|
24
|
+
def close
|
25
|
+
@file&.close
|
26
|
+
@file = nil
|
16
27
|
end
|
17
28
|
|
18
29
|
def format_json
|
@@ -54,11 +65,15 @@ module UnitF
|
|
54
65
|
end
|
55
66
|
|
56
67
|
def cover_path
|
57
|
-
"#{dirname}/cover.jpg"
|
68
|
+
["#{dirname}/cover.jpg", "#{dirname}/../cover.jpg"].each do |path|
|
69
|
+
return ::File.realpath(path) if ::File.exist?(path)
|
70
|
+
end
|
58
71
|
end
|
59
72
|
|
60
73
|
def auto_tag_path
|
61
|
-
"#{dirname}/.autotag.
|
74
|
+
["#{dirname}/.autotag", "#{dirname}/../.autotag"].each do |path|
|
75
|
+
return ::File.realpath(path) if ::File.exist?(path)
|
76
|
+
end
|
62
77
|
end
|
63
78
|
|
64
79
|
def mp3?
|
@@ -70,71 +85,128 @@ module UnitF
|
|
70
85
|
end
|
71
86
|
|
72
87
|
def cover_available?
|
73
|
-
|
88
|
+
cover_path != nil
|
74
89
|
end
|
75
90
|
|
76
91
|
def auto_cover!
|
77
|
-
|
92
|
+
raise Error, "File is not open #{self.class.name}" if tag.nil?
|
93
|
+
|
94
|
+
cover!(cover_path)
|
95
|
+
true
|
96
|
+
rescue StandardError => e
|
97
|
+
UnitF::Log.error("Failed to auto-cover file #{e}")
|
98
|
+
false
|
99
|
+
end
|
100
|
+
|
101
|
+
def manual_auto_tags
|
102
|
+
UnitF::Log.info(auto_tag_path)
|
103
|
+
tags = {}
|
104
|
+
return {} unless ::File.exist?(auto_tag_path)
|
105
|
+
::File.read(auto_tag_path).each_line do |line|
|
106
|
+
line.chomp!
|
107
|
+
UnitF::Log.info(line)
|
108
|
+
tag, value = line.split(/\s*=\s*/)
|
109
|
+
tags[tag.to_sym] = value
|
110
|
+
end
|
111
|
+
tags
|
112
|
+
rescue StandardError
|
113
|
+
{}
|
78
114
|
end
|
79
115
|
|
80
|
-
# def
|
116
|
+
# def auto_tags
|
117
|
+
# manual_tags = manual_auto_tags
|
81
118
|
# tags = {}
|
82
|
-
|
83
|
-
# ::File.
|
84
|
-
#
|
85
|
-
|
86
|
-
#
|
87
|
-
# tags[
|
119
|
+
|
120
|
+
# tags[:title] = ::File.basename(realpath.to_path)
|
121
|
+
# track = tags[:title].match(/^\s*\d+/).to_s.to_i
|
122
|
+
|
123
|
+
# if tags[:title].scan(/(\.|_|-)(\d\d\d\d(\.|-)\d\d(\.|-)\d\d)/)
|
124
|
+
# tags[:title] = ::Regexp::last_match
|
125
|
+
# else
|
126
|
+
# tags[:title].gsub!(/\.\w+$/, '')
|
127
|
+
# tags[:title].gsub!(/^\d*\s*(-|\.)*\s*/, '')
|
88
128
|
# end
|
89
|
-
|
90
|
-
#
|
91
|
-
#
|
129
|
+
|
130
|
+
# path_parts = realpath.dirname.to_path.split('/')
|
131
|
+
# tags[:album] = path_parts[-1]
|
132
|
+
# tags[:artist] = path_parts[-2]
|
133
|
+
|
134
|
+
# tags.merge(manual_auto_tags)
|
92
135
|
# end
|
93
136
|
|
94
|
-
def
|
137
|
+
def path_tags
|
95
138
|
tags = {}
|
96
139
|
|
97
140
|
tags[:title] = ::File.basename(realpath.to_path)
|
98
|
-
track = tags[:title].match(/^\s*\d+/).to_s.to_i
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
tags.
|
107
|
-
|
141
|
+
tags[:track] = tags[:title].match(/^\s*\d+/).to_s.to_i
|
142
|
+
|
143
|
+
# Specific formatting for dated radio
|
144
|
+
if tags[:title].scan(/(\.|_|-)((\d\d\d\d)(\.|-)\d\d(\.|-)\d\d(\w*))\./).any?
|
145
|
+
tags[:title] = ::Regexp.last_match[2]
|
146
|
+
tags[:year] = ::Regexp.last_match[3].to_i
|
147
|
+
else
|
148
|
+
tags[:title].gsub!(/\.\w+$/, '')
|
149
|
+
tags[:title].gsub!(/^\d*\s*(-|\.)*\s*/, '')
|
150
|
+
end
|
108
151
|
|
109
|
-
tags
|
152
|
+
tags[:artist] = path_parts[-2]
|
153
|
+
tags[:album] = tags[:album_artist] = path_parts[-1]
|
110
154
|
end
|
111
155
|
|
112
156
|
def auto_tag!
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
157
|
+
UnitF::Log.info("Auto tagging #{self}")
|
158
|
+
|
159
|
+
title = ::File.basename(realpath.to_path)
|
160
|
+
path_parts = realpath.dirname.to_path.split('/')
|
161
|
+
|
162
|
+
year = nil
|
163
|
+
|
164
|
+
# This must come before gsubbing the title
|
165
|
+
track = title.match(/^\s*\d+/).to_s.to_i
|
166
|
+
|
167
|
+
# Specific formatting for dated radio
|
168
|
+
if title.scan(/(\.|_|-)((\d\d\d\d)(\.|-)\d\d(\.|-)\d\d(\w*))\./).any?
|
169
|
+
title = ::Regexp.last_match[2]
|
170
|
+
album = path_parts[-1]
|
171
|
+
year = ::Regexp.last_match[3].to_i
|
172
|
+
else
|
173
|
+
title.gsub!(/\.\w+$/, '')
|
174
|
+
title.gsub!(/^\d*\s*(-|\.)*\s*/, '')
|
175
|
+
album = path_parts[-1]
|
176
|
+
end
|
177
|
+
|
178
|
+
artist = path_parts[-2]
|
179
|
+
|
180
|
+
tag.year = year unless year.nil?
|
181
|
+
tag.album = album
|
182
|
+
tag.artist = artist
|
183
|
+
tag.title = title
|
184
|
+
tag.track = track if track.positive?
|
185
|
+
self.album_artist = artist
|
119
186
|
end
|
120
187
|
|
121
|
-
def
|
122
|
-
|
188
|
+
def properties!(properties)
|
189
|
+
properties.each_pair do |property, value|
|
190
|
+
UnitF::Log.info("Setting #{property} to #{value}")
|
191
|
+
tag.send("#{property}=", value)
|
192
|
+
end
|
123
193
|
end
|
124
194
|
|
125
|
-
def
|
126
|
-
|
127
|
-
|
195
|
+
def update
|
196
|
+
open(auto_save: true) do |file|
|
197
|
+
yield(file) if block_given?
|
198
|
+
end
|
128
199
|
end
|
129
200
|
|
130
|
-
def open
|
131
|
-
|
201
|
+
def open(auto_save: false)
|
202
|
+
file = if flac?
|
132
203
|
UnitF::Tag::FLAC.new(to_path)
|
133
204
|
elsif mp3?
|
134
205
|
UnitF::Tag::MP3.new(to_path)
|
135
206
|
end
|
136
|
-
yield(
|
137
|
-
|
207
|
+
yield(file) if block_given?
|
208
|
+
file.save if auto_save
|
209
|
+
file.close
|
138
210
|
end
|
139
211
|
end
|
140
212
|
end
|
data/lib/unitf/tag/fileset.rb
CHANGED
@@ -1,16 +1,20 @@
|
|
1
1
|
module UnitF
|
2
2
|
module Tag
|
3
3
|
class FileSet < Array
|
4
|
+
include Helpers
|
5
|
+
|
4
6
|
def initialize(targets)
|
7
|
+
targets = [targets] if targets.is_a?(String)
|
5
8
|
targets.each do |target|
|
6
9
|
process_target(target)
|
7
10
|
end
|
8
11
|
end
|
9
12
|
|
10
13
|
def process_target(target)
|
14
|
+
UnitF::Log.debug("Processing target #{target}...")
|
11
15
|
if ::File.directory?(target)
|
12
16
|
find_files(target)
|
13
|
-
elsif
|
17
|
+
elsif valid_file?(target)
|
14
18
|
append(UnitF::Tag::File.new(target))
|
15
19
|
end
|
16
20
|
end
|
@@ -18,7 +22,8 @@ module UnitF
|
|
18
22
|
def find_files(root_path)
|
19
23
|
Find.find(root_path) do |file_path|
|
20
24
|
UnitF::Log.debug("Considering #{file_path}")
|
21
|
-
next unless
|
25
|
+
next unless valid_file?(file_path)
|
26
|
+
|
22
27
|
UnitF::Log.debug("Including #{file_path}")
|
23
28
|
append(UnitF::Tag::File.new(file_path))
|
24
29
|
end
|
data/lib/unitf/tag/flac.rb
CHANGED
@@ -22,11 +22,12 @@ module UnitF
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def cover!(file_path)
|
25
|
+
UnitF::Log.info("Setting cover #{file_path}")
|
25
26
|
pic = TagLib::FLAC::Picture.new
|
26
27
|
pic.type = TagLib::FLAC::Picture::FrontCover
|
27
|
-
pic.mime_type =
|
28
|
-
pic.description =
|
29
|
-
pic.data = ::File.
|
28
|
+
pic.mime_type = 'image/jpeg'
|
29
|
+
pic.description = 'Front Cover'
|
30
|
+
pic.data = ::File.binread(file_path)
|
30
31
|
@file.add_picture(pic)
|
31
32
|
end
|
32
33
|
|
@@ -40,7 +41,7 @@ module UnitF
|
|
40
41
|
|
41
42
|
def stats
|
42
43
|
stats = @file.audio_properties
|
43
|
-
sprintf(
|
44
|
+
sprintf('%.1fkHz/%d-bit %dkbps', stats.sample_rate / 1000.to_f, stats.bits_per_sample, stats.bitrate)
|
44
45
|
end
|
45
46
|
|
46
47
|
def dump
|
@@ -57,4 +58,4 @@ module UnitF
|
|
57
58
|
end
|
58
59
|
end
|
59
60
|
end
|
60
|
-
end
|
61
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'unitf/logging'
|
2
|
+
|
3
|
+
module UnitF
|
4
|
+
module Tag
|
5
|
+
module Helpers
|
6
|
+
def valid_file?(file_path)
|
7
|
+
::File.file?(file_path) && file_path.encode.match(/\.(flac|mp3)$/i)
|
8
|
+
rescue ArgumentError => e
|
9
|
+
UnitF::Log.error("Error processing #{file_path} - #{e.message}")
|
10
|
+
false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/unitf/tag/mp3.rb
CHANGED
@@ -7,7 +7,7 @@ module UnitF
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def stats
|
10
|
-
sprintf(
|
10
|
+
sprintf('%.1fkHz/%dkbps', @file.audio_properties.sample_rate / 1000.to_f, @file.audio_properties.bitrate)
|
11
11
|
end
|
12
12
|
|
13
13
|
def info
|
@@ -19,15 +19,16 @@ module UnitF
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def cover?
|
22
|
-
@file.id3v2_tag.frame_list('APIC').size
|
22
|
+
@file.id3v2_tag.frame_list('APIC').size.positive?
|
23
23
|
end
|
24
24
|
|
25
25
|
def cover!(file_path)
|
26
|
+
UnitF::Log.info("Setting cover #{file_path}")
|
26
27
|
apic = TagLib::ID3v2::AttachedPictureFrame.new
|
27
|
-
apic.mime_type =
|
28
|
-
apic.description =
|
28
|
+
apic.mime_type = 'image/jpeg'
|
29
|
+
apic.description = 'Cover'
|
29
30
|
apic.type = TagLib::ID3v2::AttachedPictureFrame::FrontCover
|
30
|
-
apic.picture = ::File.
|
31
|
+
apic.picture = ::File.binread(file_path)
|
31
32
|
@file.id3v2_tag.add_frame(apic)
|
32
33
|
end
|
33
34
|
|
@@ -37,7 +38,7 @@ module UnitF
|
|
37
38
|
|
38
39
|
def album_artist=(artist)
|
39
40
|
@file.id3v2_tag.remove_frames('TPE2')
|
40
|
-
frame = TagLib::ID3v2::TextIdentificationFrame.new(
|
41
|
+
frame = TagLib::ID3v2::TextIdentificationFrame.new('TPE2', TagLib::String::UTF8)
|
41
42
|
frame.text = artist
|
42
43
|
@file.id3v2_tag.add_frame(frame)
|
43
44
|
end
|
data/lib/unitf/tag/version.rb
CHANGED
data/lib/unitf/tag.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'tag/helpers'
|
3
4
|
require_relative 'tag/version'
|
4
5
|
require_relative 'tag/file'
|
5
6
|
require_relative 'tag/fileset'
|
@@ -10,66 +11,33 @@ require 'unitf/logging'
|
|
10
11
|
|
11
12
|
module UnitF
|
12
13
|
module Tag
|
13
|
-
class
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
@logger.add_writer(UnitF::Logging::ConsoleWriter.new)
|
20
|
-
end
|
21
|
-
@logger
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.update(file_path)
|
25
|
-
UnitF::Tag::File.new(file_path).open do |file|
|
26
|
-
yield file
|
27
|
-
file.save || (raise UnitF::Tag::Error, "Failed to save file #{file_path}")
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.valid_file?(file_path)
|
32
|
-
::File.file?(file_path) && file_path.encode.match(/\.(flac|mp3)$/i)
|
33
|
-
rescue ArgumentError => e
|
34
|
-
logger.error("Error processing #{file_path} - #{e.message}")
|
35
|
-
false
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.process_target(target)
|
39
|
-
if ::File.directory?(target)
|
40
|
-
find_files(target)
|
41
|
-
elsif valid_file?(target)
|
42
|
-
[UnitF::Tag::File.new(target)]
|
43
|
-
else
|
44
|
-
[]
|
14
|
+
class << self
|
15
|
+
def update(file_path)
|
16
|
+
UnitF::Tag::File.new(file_path).update do |file|
|
17
|
+
yield file
|
18
|
+
file.save || (raise UnitF::Tag::Error, "Failed to save file #{file_path}")
|
19
|
+
end
|
45
20
|
end
|
46
|
-
end
|
47
21
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
files.each do |file|
|
61
|
-
file.open do |o|
|
62
|
-
case format
|
63
|
-
when :json
|
64
|
-
buff << o.info
|
65
|
-
when :line
|
66
|
-
puts o.format_line
|
67
|
-
else
|
68
|
-
o.print
|
22
|
+
def list(files, format: :json)
|
23
|
+
buff = []
|
24
|
+
files.each do |file|
|
25
|
+
file.open do |o|
|
26
|
+
case format
|
27
|
+
when :json
|
28
|
+
buff << o.info
|
29
|
+
when :line
|
30
|
+
puts o.format_line
|
31
|
+
else
|
32
|
+
o.print
|
33
|
+
end
|
69
34
|
end
|
70
35
|
end
|
36
|
+
puts JSON.pretty_generate(buff) if format == :json
|
71
37
|
end
|
72
|
-
puts JSON.pretty_generate(buff) if format == :json
|
73
38
|
end
|
39
|
+
|
40
|
+
class Error < StandardError; end
|
41
|
+
class MissingCover < Error; end
|
74
42
|
end
|
75
43
|
end
|
data/unitf-tag.gemspec
CHANGED
@@ -1,32 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative 'lib/unitf/tag/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name =
|
6
|
+
spec.name = 'unitf-tag'
|
7
7
|
spec.version = Unitf::Tag::VERSION
|
8
|
-
spec.authors = [
|
9
|
-
spec.email = [
|
8
|
+
spec.authors = ['Matt Baron']
|
9
|
+
spec.email = ['mwb@unitf.net']
|
10
10
|
|
11
|
-
spec.summary =
|
11
|
+
spec.summary = 'Audio File Tagging'
|
12
12
|
spec.description = spec.summary
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
15
|
-
spec.required_ruby_version =
|
13
|
+
spec.homepage = 'https://github.com/mattbaron/unitf-tag'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
spec.required_ruby_version = '>= 3.0.0'
|
16
16
|
|
17
|
-
spec.metadata[
|
17
|
+
spec.metadata['allowed_push_host'] = 'https://www.rubygems.org'
|
18
18
|
|
19
|
-
spec.metadata[
|
20
|
-
spec.metadata[
|
21
|
-
spec.metadata[
|
19
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
20
|
+
spec.metadata['source_code_uri'] = 'https://github.com/mattbaron/unitf-tag'
|
21
|
+
spec.metadata['changelog_uri'] = 'https://github.com/mattbaron/unitf-tag/CHANGELOG.md'
|
22
22
|
|
23
23
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
24
24
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
25
25
|
end
|
26
|
-
spec.bindir =
|
26
|
+
spec.bindir = 'exe'
|
27
27
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
28
|
-
spec.require_paths = [
|
28
|
+
spec.require_paths = ['lib']
|
29
29
|
|
30
|
-
spec.add_dependency
|
31
|
-
spec.add_dependency
|
30
|
+
#spec.add_dependency 'taglib-ruby', '1.1.2'
|
31
|
+
spec.add_dependency 'taglib-ruby'
|
32
|
+
spec.add_dependency 'unitf-logging'
|
32
33
|
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unitf-tag
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.25
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Baron
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-03-24 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: taglib-ruby
|
@@ -57,8 +56,6 @@ files:
|
|
57
56
|
- LICENSE.txt
|
58
57
|
- README.md
|
59
58
|
- Rakefile
|
60
|
-
- bin/console
|
61
|
-
- bin/setup
|
62
59
|
- bin/test.rb
|
63
60
|
- exe/tag
|
64
61
|
- exe/unitf-autotags
|
@@ -67,6 +64,7 @@ files:
|
|
67
64
|
- lib/unitf/tag/file.rb
|
68
65
|
- lib/unitf/tag/fileset.rb
|
69
66
|
- lib/unitf/tag/flac.rb
|
67
|
+
- lib/unitf/tag/helpers.rb
|
70
68
|
- lib/unitf/tag/mp3.rb
|
71
69
|
- lib/unitf/tag/version.rb
|
72
70
|
- unitf-tag.gemspec
|
@@ -78,7 +76,6 @@ metadata:
|
|
78
76
|
homepage_uri: https://github.com/mattbaron/unitf-tag
|
79
77
|
source_code_uri: https://github.com/mattbaron/unitf-tag
|
80
78
|
changelog_uri: https://github.com/mattbaron/unitf-tag/CHANGELOG.md
|
81
|
-
post_install_message:
|
82
79
|
rdoc_options: []
|
83
80
|
require_paths:
|
84
81
|
- lib
|
@@ -86,15 +83,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
86
83
|
requirements:
|
87
84
|
- - ">="
|
88
85
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
86
|
+
version: 3.0.0
|
90
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
88
|
requirements:
|
92
89
|
- - ">="
|
93
90
|
- !ruby/object:Gem::Version
|
94
91
|
version: '0'
|
95
92
|
requirements: []
|
96
|
-
rubygems_version: 3.3
|
97
|
-
signing_key:
|
93
|
+
rubygems_version: 3.6.3
|
98
94
|
specification_version: 4
|
99
95
|
summary: Audio File Tagging
|
100
96
|
test_files: []
|
data/bin/console
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "bundler/setup"
|
5
|
-
require "unitf/tag"
|
6
|
-
|
7
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
-
# with your gem easier. You can also use a different console, if you like.
|
9
|
-
|
10
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
-
# require "pry"
|
12
|
-
# Pry.start
|
13
|
-
|
14
|
-
require "irb"
|
15
|
-
IRB.start(__FILE__)
|