flacky 0.9.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/flacky +2 -0
- data/flacky.gemspec +3 -1
- data/lib/flacky/cli.rb +22 -5
- data/lib/flacky/flac_metadata_importer.rb +50 -0
- data/lib/flacky/flac_tagger.rb +49 -0
- data/lib/flacky/metadata_generator.rb +34 -10
- data/lib/flacky/mp3_convertor.rb +64 -20
- data/lib/flacky/mp3_tagger.rb +79 -0
- data/lib/flacky/version.rb +1 -1
- data/spec/fixtures/silence.flac +0 -0
- data/spec/flacky/flac_tagger_spec.rb +99 -0
- metadata +9 -7
- data/lib/flacky/tagger.rb +0 -27
- data/spec/flacky/tagger_spec.rb +0 -67
data/bin/flacky
CHANGED
data/flacky.gemspec
CHANGED
@@ -17,9 +17,11 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
|
20
|
+
gem.required_ruby_version = ">= 1.9.3"
|
21
|
+
|
20
22
|
gem.add_dependency 'thor'
|
21
23
|
gem.add_dependency 'nokogiri'
|
22
|
-
gem.add_dependency '
|
24
|
+
gem.add_dependency 'taglib-ruby'
|
23
25
|
|
24
26
|
gem.add_development_dependency 'minitest'
|
25
27
|
gem.add_development_dependency 'vcr'
|
data/lib/flacky/cli.rb
CHANGED
@@ -5,6 +5,7 @@ require 'json'
|
|
5
5
|
require 'thor'
|
6
6
|
|
7
7
|
require 'flacky'
|
8
|
+
require 'flacky/flac_metadata_importer'
|
8
9
|
require 'flacky/metadata_generator'
|
9
10
|
require 'flacky/mp3_convertor'
|
10
11
|
|
@@ -14,8 +15,8 @@ module Flacky
|
|
14
15
|
|
15
16
|
include Thor::Actions
|
16
17
|
|
17
|
-
desc "
|
18
|
-
def
|
18
|
+
desc "generate_json <root_path>", "Generate and populate metadata as JSON"
|
19
|
+
def generate_json(root_dir = ENV['PWD'])
|
19
20
|
start_dir = File.join(File.expand_path(root_dir), '**/*.flac')
|
20
21
|
Dir.glob(start_dir).map { |f| File.dirname(f) }.uniq.each do |dir|
|
21
22
|
mdf = File.join(dir, "metadata.json")
|
@@ -25,6 +26,11 @@ module Flacky
|
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
29
|
+
desc "import_json [file ...]|[**/*.flac ...]", "Import metadata JSON into Flac files"
|
30
|
+
def import_json(*args)
|
31
|
+
args.each { |glob| import_metadata_for_files(glob) }
|
32
|
+
end
|
33
|
+
|
28
34
|
desc "missing_urls <root_path>", "List all metadata files with missing URLs"
|
29
35
|
method_option :print0, :aliases => "-0", :type => :boolean
|
30
36
|
def missing_urls(root_dir = ENV['PWD'])
|
@@ -43,14 +49,14 @@ module Flacky
|
|
43
49
|
end
|
44
50
|
end
|
45
51
|
|
46
|
-
desc "to_mp3 [file ...]|[**/*.flac ...]", "Convert Flac files to MP3 files"
|
52
|
+
desc "to_mp3 [file ...]|[**/*.flac ...] [options]", "Convert Flac files to MP3 files"
|
47
53
|
method_option :destination, :aliases => "-d",
|
48
54
|
:desc => "Sets optional destination directory"
|
49
55
|
method_option :'lame-opts', :aliases => "-l",
|
50
|
-
:default => "--vbr-new -V 0 -b 320",
|
56
|
+
:default => "--vbr-new --verbose -V 0 -b 320",
|
51
57
|
:desc => "Set the lame encoding arguments"
|
52
58
|
def to_mp3(*args)
|
53
|
-
%w{flac
|
59
|
+
%w{flac lame}.each do |cmd|
|
54
60
|
abort "Command #{cmd} must be on your PATH" unless %x{which #{cmd}}
|
55
61
|
end
|
56
62
|
|
@@ -75,6 +81,17 @@ module Flacky
|
|
75
81
|
end
|
76
82
|
end
|
77
83
|
|
84
|
+
def import_metadata_for_files(glob)
|
85
|
+
Dir.glob(glob).each do |file|
|
86
|
+
next unless file =~ /\.flac$/
|
87
|
+
|
88
|
+
say("Processing #{file}...", :cyan)
|
89
|
+
response = Flacky::FlacMetadataImporter.new(file).import!
|
90
|
+
say("Imported #{response.metadata_filename} into #{file} " +
|
91
|
+
"#{duration(response.elapsed)}", :yellow)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
78
95
|
def duration(total)
|
79
96
|
minutes = (total / 60).to_i
|
80
97
|
seconds = (total - (minutes * 60))
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'flacky/flac_tagger'
|
4
|
+
|
5
|
+
module Flacky
|
6
|
+
|
7
|
+
class FlacMetadataImporter
|
8
|
+
|
9
|
+
def initialize(file)
|
10
|
+
@file = file
|
11
|
+
end
|
12
|
+
|
13
|
+
def import!
|
14
|
+
return Resonse.new(nil, 0) if ! File.exists?(metadata_file)
|
15
|
+
|
16
|
+
md = JSON.parse(IO.read(metadata_file))
|
17
|
+
|
18
|
+
elapsed = Benchmark.measure do
|
19
|
+
FlacTagger.update(@file) do
|
20
|
+
trackn_good = self["TRACKNUMBER"] && self["TRACKNUMBER"].to_i > 0
|
21
|
+
discn_good = self["DISCNUMBER"] && self["DISCNUMBER"].to_i > 0
|
22
|
+
md_good = md["flac"] && md["flac"]["totaltracks"] \
|
23
|
+
&& md["flac"]["totaltracks"].is_a?(Array)
|
24
|
+
totaltracks = md["flac"]["totaltracks"][self["DISCNUMBER"].to_i - 1]
|
25
|
+
|
26
|
+
%w{artist album genre style mood fileowner}.each do |t|
|
27
|
+
tag(t, md["flac"][t]) if md["flac"] && md["flac"][t]
|
28
|
+
end
|
29
|
+
|
30
|
+
tag "DATE", md["flac"]["year"] if md["flac"]["year"]
|
31
|
+
|
32
|
+
if trackn_good && discn_good && md_good
|
33
|
+
tag('TOTALTRACKS', totaltracks.to_s)
|
34
|
+
tag('TOTALDISCS', md["flac"]["totaltracks"].size.to_s)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Response.new(metadata_file, elapsed.real)
|
40
|
+
end
|
41
|
+
|
42
|
+
Response = Struct.new(:metadata_filename, :elapsed)
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def metadata_file
|
47
|
+
@metadata_file ||= File.join(File.dirname(@file), "metadata.json")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'taglib'
|
4
|
+
|
5
|
+
module Flacky
|
6
|
+
class FlacTagger
|
7
|
+
|
8
|
+
def self.update(file, &block)
|
9
|
+
instance = self.new(file)
|
10
|
+
instance.instance_eval(&block)
|
11
|
+
instance.update!
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(file)
|
15
|
+
@taglib = TagLib::FLAC::File.new(file)
|
16
|
+
@tag = @taglib.xiph_comment
|
17
|
+
end
|
18
|
+
|
19
|
+
def [](attr)
|
20
|
+
result = @tag.field_list_map[attr]
|
21
|
+
|
22
|
+
if result.nil?
|
23
|
+
nil
|
24
|
+
elsif result.is_a?(Array) && result.size == 1
|
25
|
+
result.first
|
26
|
+
else
|
27
|
+
result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def find(attr)
|
32
|
+
key = @tag.field_list_map.keys.find { |key| key =~ /#{attr}/i }
|
33
|
+
key ? self[key] : nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def tag(name, value)
|
37
|
+
@tag.add_field(name.to_s.upcase, value, true)
|
38
|
+
end
|
39
|
+
|
40
|
+
def cleanup
|
41
|
+
@taglib.close
|
42
|
+
end
|
43
|
+
|
44
|
+
def update!
|
45
|
+
@taglib.save
|
46
|
+
cleanup
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: UTF-8 -*-
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'taglib'
|
4
4
|
|
5
5
|
require 'flacky/core_ext'
|
6
6
|
require 'flacky/scraper'
|
@@ -19,16 +19,23 @@ module Flacky
|
|
19
19
|
flacs = Dir.glob(File.join(dir, '*.flac'))
|
20
20
|
return Hash.new if flacs.empty?
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
result = Hash.new
|
23
|
+
result["totaltracks"] = []
|
24
|
+
|
25
|
+
flacs.each do |flac|
|
26
|
+
md = read_flac_metadata(flac)
|
27
|
+
track_total = (md["totaltracks"] || -1).to_i
|
28
|
+
disc_number = (md["discnumber"] || -1).to_i
|
29
|
+
|
30
|
+
next if track_total < 0 || disc_number < 0
|
31
|
+
next if result["totaltracks"][disc_number - 1]
|
32
|
+
|
33
|
+
result["totaltracks"][disc_number - 1] = track_total
|
34
|
+
|
35
|
+
common_tags.each { |t| result[t] = md[t] if md[t] }
|
27
36
|
end
|
37
|
+
result["year"] = result.delete("date") if result["date"]
|
28
38
|
|
29
|
-
info.each_pair { |k,v| v.force_encoding('UTF-8') if v.is_a? String }
|
30
|
-
result = Hash.new
|
31
|
-
common_tags.each { |t| result[t] = info[t] }
|
32
39
|
result
|
33
40
|
end
|
34
41
|
|
@@ -55,7 +62,24 @@ module Flacky
|
|
55
62
|
end
|
56
63
|
|
57
64
|
def common_tags
|
58
|
-
%w[
|
65
|
+
%w[artist album date year genre style mood fileowner].freeze
|
66
|
+
end
|
67
|
+
|
68
|
+
def read_flac_metadata(flac)
|
69
|
+
info = TagLib::FLAC::File.open(flac) do |file|
|
70
|
+
file.xiph_comment.field_list_map
|
71
|
+
end
|
72
|
+
|
73
|
+
info.each_pair do |k, v|
|
74
|
+
value = Array(v).first
|
75
|
+
value.force_encoding('UTF-8') if v.is_a? String
|
76
|
+
info[k] = value
|
77
|
+
end
|
78
|
+
info.keys.each do |key|
|
79
|
+
info[key.downcase] = info.delete(key)
|
80
|
+
end
|
81
|
+
|
82
|
+
info
|
59
83
|
end
|
60
84
|
end
|
61
85
|
end
|
data/lib/flacky/mp3_convertor.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
|
+
require 'flacky/flac_tagger'
|
4
|
+
require 'flacky/mp3_tagger'
|
5
|
+
|
3
6
|
module Flacky
|
4
7
|
|
5
8
|
class Mp3Convertor
|
@@ -9,19 +12,16 @@ module Flacky
|
|
9
12
|
@dest_root = opts[:dest_root]
|
10
13
|
end
|
11
14
|
|
12
|
-
def convert_file!(
|
13
|
-
|
14
|
-
if dest_root
|
15
|
-
dst = File.join(dest_root, dst)
|
16
|
-
FileUtils.mkdir_p File.dirname(dst)
|
17
|
-
end
|
15
|
+
def convert_file!(flac_file)
|
16
|
+
mp3_file = calculate_mp3_filename(flac_file)
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
elapsed = Benchmark.measure do
|
19
|
+
FileUtils.mkdir_p File.dirname(mp3_file)
|
20
|
+
transcode_file(flac_file, mp3_file)
|
21
|
+
tag_file(flac_file, mp3_file)
|
22
|
+
end
|
22
23
|
|
23
|
-
elapsed
|
24
|
-
Response.new(dst, elapsed.real)
|
24
|
+
Response.new(mp3_file, elapsed.real)
|
25
25
|
end
|
26
26
|
|
27
27
|
Response = Struct.new(:mp3_filename, :elapsed)
|
@@ -30,18 +30,62 @@ module Flacky
|
|
30
30
|
|
31
31
|
attr_reader :lame_opts, :dest_root
|
32
32
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
33
|
+
def calculate_mp3_filename(flac_file)
|
34
|
+
mp3_file = flac_file.sub(/\.flac$/, ".mp3")
|
35
|
+
mp3_file = File.join(dest_root, mp3_file) if dest_root
|
36
|
+
File.expand_path(mp3_file)
|
37
|
+
end
|
38
|
+
|
39
|
+
def transcode_file(flac_file, mp3_file)
|
40
|
+
%x{flac -dcs "#{flac_file}" | lame #{lame_opts} - "#{mp3_file}"}
|
41
|
+
end
|
42
|
+
|
43
|
+
def tag_file(flac_file, mp3_file)
|
44
|
+
flac_tags = Flacky::FlacTagger.new(flac_file)
|
45
|
+
track = track_tag(flac_tags)
|
46
|
+
disc = disc_tag(flac_tags)
|
47
|
+
comment = comment_tag(flac_tags)
|
48
|
+
|
49
|
+
Flacky::Mp3Tagger.update(mp3_file) do
|
50
|
+
tag "album", flac_tags.find(:album)
|
51
|
+
tag "artist", flac_tags.find(:artist)
|
52
|
+
tag "title", flac_tags.find(:title)
|
53
|
+
tag "year", flac_tags.find(:date).to_i
|
54
|
+
tag "genre", flac_tags.find(:genre)
|
55
|
+
tag "track", track
|
56
|
+
tag "disc", disc
|
57
|
+
tag "comment", comment
|
58
|
+
end
|
59
|
+
|
60
|
+
flac_tags.cleanup
|
36
61
|
end
|
37
62
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
63
|
+
def track_tag(flac_tags)
|
64
|
+
track_number = flac_tags.find(:tracknumber) || "0"
|
65
|
+
track_total = flac_tags.find(:totaltracks) || "1"
|
66
|
+
|
67
|
+
"#{track_number}/#{track_total}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def disc_tag(flac_tags)
|
71
|
+
disc_number = flac_tags.find(:discnumber) || "0"
|
72
|
+
disc_total = flac_tags.find(:totaldiscs) || "1"
|
73
|
+
|
74
|
+
"#{disc_number}/#{disc_total}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def comment_tag(flac_tags)
|
78
|
+
comment = []
|
79
|
+
if owner = flac_tags.find(:fileowner)
|
80
|
+
comment << "o=#{owner}"
|
81
|
+
end
|
82
|
+
(flac_tags.find(:style) || "").split(';').each do |style|
|
83
|
+
comment << "s=#{style}"
|
84
|
+
end
|
85
|
+
(flac_tags.find(:mood) || "").split(';').each do |mood|
|
86
|
+
comment << "m=#{mood}"
|
44
87
|
end
|
88
|
+
comment.join("\n")
|
45
89
|
end
|
46
90
|
end
|
47
91
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'taglib'
|
4
|
+
|
5
|
+
module Flacky
|
6
|
+
class Mp3Tagger
|
7
|
+
|
8
|
+
def self.update(file, &block)
|
9
|
+
instance = self.new(file)
|
10
|
+
instance.instance_eval(&block)
|
11
|
+
instance.update!
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(file)
|
15
|
+
@taglib = TagLib::MPEG::File.new(file)
|
16
|
+
@tag = @taglib.id3v2_tag
|
17
|
+
end
|
18
|
+
|
19
|
+
def [](attr)
|
20
|
+
result = @tag.field_list_map[attr]
|
21
|
+
|
22
|
+
if result.nil?
|
23
|
+
nil
|
24
|
+
elsif result.is_a?(Array) && result.size == 1
|
25
|
+
result.first
|
26
|
+
else
|
27
|
+
result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def find(attr)
|
32
|
+
key = @tag.field_list_map.keys.find { |key| key =~ /#{attr}/i }
|
33
|
+
key ? self[key] : nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def tag(name, value)
|
37
|
+
if TAGS.include?(name.to_sym)
|
38
|
+
@tag.public_send("#{name}=", value)
|
39
|
+
elsif name =~ /track/i
|
40
|
+
@tag.add_frame(new_text_frame("TRCK", value))
|
41
|
+
elsif name =~ /disc/i
|
42
|
+
@tag.add_frame(new_text_frame("TPOS", value))
|
43
|
+
elsif name =~ /comment/i
|
44
|
+
@tag.add_frame(new_comment_frame(value))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def cleanup
|
49
|
+
@taglib.close
|
50
|
+
end
|
51
|
+
|
52
|
+
def update!
|
53
|
+
@taglib.save
|
54
|
+
cleanup
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
TAGS = [:album, :artist, :title, :year, :genre].freeze
|
60
|
+
|
61
|
+
def encoding
|
62
|
+
TagLib::String::Latin1
|
63
|
+
end
|
64
|
+
|
65
|
+
def new_text_frame(type, value)
|
66
|
+
frame = TagLib::ID3v2::TextIdentificationFrame.new(type, encoding)
|
67
|
+
frame.text = value
|
68
|
+
frame
|
69
|
+
end
|
70
|
+
|
71
|
+
def new_comment_frame(value)
|
72
|
+
frame = TagLib::ID3v2::CommentsFrame.new
|
73
|
+
frame.text_encoding = encoding
|
74
|
+
frame.language = "eng"
|
75
|
+
frame.text = value
|
76
|
+
frame
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/flacky/version.rb
CHANGED
data/spec/fixtures/silence.flac
CHANGED
Binary file
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'mocha/setup'
|
5
|
+
require 'flacky/flac_tagger'
|
6
|
+
|
7
|
+
describe Flacky::FlacTagger do
|
8
|
+
|
9
|
+
let(:flac_file) do
|
10
|
+
File.join(File.dirname(__FILE__), '../fixtures/silence.flac')
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:tagger) do
|
14
|
+
Flacky::FlacTagger.new(flac_file)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "when writing tags" do
|
18
|
+
|
19
|
+
let(:tag) do
|
20
|
+
mock('xiph_comment')
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:taglib_flac) do
|
24
|
+
mock = TagLib::FLAC::File.new(flac_file)
|
25
|
+
mock.stubs(:save).returns(true)
|
26
|
+
mock.stubs(:xiph_comment).returns(tag)
|
27
|
+
mock
|
28
|
+
end
|
29
|
+
|
30
|
+
before do
|
31
|
+
taglib_flac
|
32
|
+
TagLib::FLAC::File.stubs(:new).returns(taglib_flac)
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#tag" do
|
36
|
+
it "sets a tag if none exist" do
|
37
|
+
tag.expects(:add_field).with("DISCNUMBER", "1", true)
|
38
|
+
|
39
|
+
tagger.tag "DISCNUMBER", "1"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "sets a tag if one exists" do
|
43
|
+
tag.expects(:add_field).with("TITLE", "Foopants", true)
|
44
|
+
|
45
|
+
tagger.tag "TITLE", "Foopants"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe ".update" do
|
50
|
+
|
51
|
+
it "add the tag and updates" do
|
52
|
+
tag.expects(:add_field).with("ARTIST", "The MiniTest", true)
|
53
|
+
taglib_flac.expects(:save)
|
54
|
+
taglib_flac.expects(:close).at_least_once
|
55
|
+
|
56
|
+
Flacky::FlacTagger.update(flac_file) do
|
57
|
+
tag "ARTIST", "The MiniTest"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "when reading" do
|
64
|
+
|
65
|
+
after do
|
66
|
+
tagger.cleanup
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "#find" do
|
70
|
+
|
71
|
+
it "returns nil if attribute isn't found" do
|
72
|
+
tagger.find("haha").must_be_nil
|
73
|
+
end
|
74
|
+
|
75
|
+
it "returns a string if tag value array only has only one element" do
|
76
|
+
tagger.find("GENRE").must_equal "Avantgarde"
|
77
|
+
end
|
78
|
+
|
79
|
+
it "matches case insensitive attribute matches" do
|
80
|
+
tagger.find("artist").must_equal "Fletcher Nichol"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#[]" do
|
85
|
+
|
86
|
+
it "returns nil if attribute isn't found" do
|
87
|
+
tagger["nope"].must_be_nil
|
88
|
+
end
|
89
|
+
|
90
|
+
it "returns a string if tag value array only has only one element" do
|
91
|
+
tagger["GENRE"].must_equal "Avantgarde"
|
92
|
+
end
|
93
|
+
|
94
|
+
it "returns and array if tag value has multiple elements" do
|
95
|
+
tagger["MULTIPLE"].must_equal ["One", "Two"]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flacky
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-02-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
@@ -44,7 +44,7 @@ dependencies:
|
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
47
|
+
name: taglib-ruby
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
@@ -158,17 +158,19 @@ files:
|
|
158
158
|
- lib/flacky.rb
|
159
159
|
- lib/flacky/cli.rb
|
160
160
|
- lib/flacky/core_ext.rb
|
161
|
+
- lib/flacky/flac_metadata_importer.rb
|
162
|
+
- lib/flacky/flac_tagger.rb
|
161
163
|
- lib/flacky/metadata_generator.rb
|
162
164
|
- lib/flacky/mp3_convertor.rb
|
165
|
+
- lib/flacky/mp3_tagger.rb
|
163
166
|
- lib/flacky/scraper.rb
|
164
|
-
- lib/flacky/tagger.rb
|
165
167
|
- lib/flacky/version.rb
|
166
168
|
- spec/fixtures/silence.flac
|
167
169
|
- spec/fixtures/vcr_cassettes/audioslave_revelations.yml
|
168
170
|
- spec/fixtures/vcr_cassettes/bend_sinister_small_fame.yml
|
169
171
|
- spec/fixtures/vcr_cassettes/rush_moving_pictures.yml
|
172
|
+
- spec/flacky/flac_tagger_spec.rb
|
170
173
|
- spec/flacky/scraper_spec.rb
|
171
|
-
- spec/flacky/tagger_spec.rb
|
172
174
|
homepage: https://github.com/fnichol/flacky
|
173
175
|
licenses: []
|
174
176
|
post_install_message:
|
@@ -180,7 +182,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
180
182
|
requirements:
|
181
183
|
- - ! '>='
|
182
184
|
- !ruby/object:Gem::Version
|
183
|
-
version:
|
185
|
+
version: 1.9.3
|
184
186
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
185
187
|
none: false
|
186
188
|
requirements:
|
@@ -198,5 +200,5 @@ test_files:
|
|
198
200
|
- spec/fixtures/vcr_cassettes/audioslave_revelations.yml
|
199
201
|
- spec/fixtures/vcr_cassettes/bend_sinister_small_fame.yml
|
200
202
|
- spec/fixtures/vcr_cassettes/rush_moving_pictures.yml
|
203
|
+
- spec/flacky/flac_tagger_spec.rb
|
201
204
|
- spec/flacky/scraper_spec.rb
|
202
|
-
- spec/flacky/tagger_spec.rb
|
data/lib/flacky/tagger.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
require 'flacinfo'
|
4
|
-
|
5
|
-
module Flacky
|
6
|
-
class Tagger
|
7
|
-
def self.update(flac_file, &block)
|
8
|
-
instance = self.new(flac_file)
|
9
|
-
instance.instance_eval(&block)
|
10
|
-
instance.update!
|
11
|
-
end
|
12
|
-
|
13
|
-
def initialize(flac_file)
|
14
|
-
@flac_file = flac_file
|
15
|
-
@flac = FlacInfo.new(@flac_file)
|
16
|
-
end
|
17
|
-
|
18
|
-
def tag(name, value)
|
19
|
-
@flac.comment_del(name) if @flac.tags.keys.include?(name)
|
20
|
-
@flac.comment_add("#{name}=#{value}")
|
21
|
-
end
|
22
|
-
|
23
|
-
def update!()
|
24
|
-
@flac.update!
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/spec/flacky/tagger_spec.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
require 'minitest/autorun'
|
4
|
-
require 'mocha/setup'
|
5
|
-
require 'flacky/tagger'
|
6
|
-
|
7
|
-
describe Flacky::Tagger do
|
8
|
-
let(:flac_file) do
|
9
|
-
File.join(File.dirname(__FILE__), '../fixtures/silence.flac')
|
10
|
-
end
|
11
|
-
|
12
|
-
let(:tagger) do
|
13
|
-
Flacky::Tagger.new(flac_file)
|
14
|
-
end
|
15
|
-
|
16
|
-
let(:flacinfo) do
|
17
|
-
mock = FlacInfo.new(flac_file)
|
18
|
-
mock.stubs(:tags).returns({ 'Title' => 'Silence' })
|
19
|
-
mock.stubs(:update!).returns(true)
|
20
|
-
mock
|
21
|
-
end
|
22
|
-
|
23
|
-
describe "#tag" do
|
24
|
-
it "adds a new comment tag if none exist" do
|
25
|
-
flacinfo.expects(:comment_add).with('DISCNUMBER=1').returns(true)
|
26
|
-
FlacInfo.stubs(:new).returns(flacinfo)
|
27
|
-
|
28
|
-
tagger.tag "DISCNUMBER", "1"
|
29
|
-
end
|
30
|
-
|
31
|
-
it "overwrites a comment tag if one exists" do
|
32
|
-
flacinfo.expects(:comment_del).with('Title').returns(true)
|
33
|
-
flacinfo.expects(:comment_add).with('Title=Le Silence').returns(true)
|
34
|
-
FlacInfo.stubs(:new).returns(flacinfo)
|
35
|
-
|
36
|
-
tagger.tag "Title", "Le Silence"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
describe "#update!" do
|
41
|
-
it "calls update! on the FlacInfo object" do
|
42
|
-
flacinfo.expects(:update!).returns(true)
|
43
|
-
FlacInfo.stubs(:new).returns(flacinfo)
|
44
|
-
|
45
|
-
tagger.update!
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
describe ".update" do
|
50
|
-
it "adds the tag and updates" do
|
51
|
-
flacinfo.expects(:comment_add).with('DISCNUMBER=1').returns(true)
|
52
|
-
flacinfo.expects(:update!).returns(true)
|
53
|
-
FlacInfo.stubs(:new).returns(flacinfo)
|
54
|
-
|
55
|
-
Flacky::Tagger.update(flac_file) do
|
56
|
-
tag "DISCNUMBER", "1"
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# it "does stuff" do
|
62
|
-
# Flacky::Tagger.update('file') do
|
63
|
-
# tag 'MOOD', "yep"
|
64
|
-
# tag 'FILEOWNER', "fletcher"
|
65
|
-
# end
|
66
|
-
# end
|
67
|
-
end
|