nicoloid 1.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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'termcolor'
4
+
5
+ # Specify your gem's dependencies in nicoloid.gemspec
6
+ gemspec
data/README.mkd ADDED
@@ -0,0 +1,95 @@
1
+ # Nicoloid - Download video from nicovideo and convert to mp3
2
+
3
+ __OWN YOUR RISK__
4
+
5
+ ## Note
6
+
7
+ * This tool is optimized for VOCALOID.
8
+ * If video name contains VOCALOID names, this tool will put to artist tag in ID3.
9
+
10
+ ## Requirement
11
+
12
+ * Ruby 1.9+ (Ruby 1.9.2+ is supported)
13
+ * ffmpeg
14
+
15
+ ## How to use
16
+
17
+ 1. write config in yaml, format is below
18
+ 2. run `nicoloid /path/to/config.yml`
19
+
20
+ ## Configuration
21
+
22
+ account:
23
+ mail: your_mail
24
+ password: your_password
25
+
26
+ directories:
27
+ temporary: temporary_directory
28
+ output: mp3_directory
29
+
30
+ ffmpeg: path_to_ffmpeg
31
+
32
+ # if you use ranking as source
33
+ source:
34
+ from: ranking
35
+ method: ranking_method
36
+ span: ranking_span
37
+ category: ranking_category
38
+
39
+ # if you use mylist as source
40
+ # (tbd)
41
+
42
+ # the followings are optional.
43
+
44
+ proxy:
45
+ host: proxy_host
46
+ port: proxy_port
47
+
48
+ limit: limit_count_of_videos
49
+
50
+ ### Note
51
+
52
+ #### output directory
53
+
54
+ * __output directory will be wiped__ all its including files before converting. please move file which you need.
55
+ * output mp3-s will be saved in output directory.
56
+
57
+ #### Temporary directory
58
+
59
+ * it will be created automatically before converting, and deleted after converting.
60
+
61
+ #### What's a ranking_method and span?
62
+
63
+ * Niconico ranking url includes method, span and category.
64
+
65
+ http://www.nicovideo.jp/ranking/__METHOD__/__SPAN__/__CATEGORY__
66
+
67
+ Example: <http://www.nicovideo.jp/ranking/fav/daily/vocaloid>
68
+
69
+ source:
70
+ method: fav
71
+ span: daily
72
+ category: vocaloid
73
+
74
+ ## License
75
+
76
+ MIT Licence
77
+
78
+ (c) Shota Fukumori 2011
79
+
80
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
81
+ > of this software and associated documentation files (the "Software"), to deal
82
+ > in the Software without restriction, including without limitation the rights
83
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
84
+ > copies of the Software, and to permit persons to whom the Software is
85
+ > furnished to do so, subject to the following conditions:
86
+ > The above copyright notice and this permission notice shall be included in
87
+ > all copies or substantial portions of the Software.
88
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
89
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
90
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
91
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
92
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
93
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
94
+ > THE SOFTWARE.
95
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/bin/nicoloid ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # vim: filetype=ruby
3
+
4
+ require_relative "../lib/nicoloid"
5
+
6
+ Nicoloid.run ARGV
data/lib/nicoloid.rb ADDED
@@ -0,0 +1,286 @@
1
+ #-*- coding:utf-8 -*-
2
+
3
+ # nicoloid.rb
4
+ # Author: Shota Fukumori (sora_h) <sorah@tubusu.net>
5
+ # License: MIT Licence
6
+ # The MIT License {{{
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ # THE SOFTWARE.
24
+ #}}}
25
+
26
+ require 'rubygems'
27
+ require 'niconico'
28
+ require 'yaml'
29
+ require 'fileutils'
30
+ require 'taglib'
31
+ require 'termcolor'
32
+
33
+ frame_factory = TagLib::ID3v2::FrameFactory.instance
34
+ frame_factory.default_text_encoding = TagLib::String::UTF8
35
+
36
+ class File
37
+ NULL ||= /mswin/u =~ RUBY_PLATFORM ? 'NUL' : '/dev/null'
38
+ end
39
+
40
+ class Nicoloid
41
+
42
+ VOCALOIDS = %w(初音ミク
43
+ 鏡音リン
44
+ 鏡音レン
45
+ 巡音ルカ
46
+ KAITO
47
+ MEIKO
48
+ 重音テト
49
+ GUMI
50
+ めぐっぽいど
51
+ Megpoid
52
+ がくっぽいど
53
+ 神威がくぽ
54
+ がくぽ
55
+ VY1
56
+ 歌愛ユキ
57
+ )
58
+ VOCALOIDS_ALIAS = {"Megpoid" => "GUMI",
59
+ "めぐっぽいど" => "GUMI",
60
+ "がくぽ" => "神威がくぽ",
61
+ "がくっぽいど" => "神威がくぽ",
62
+ "megpoid" => "GUMI"}
63
+
64
+ VOCALOIDS_SORTING = {"初音ミク" => "Hatsune Miku",
65
+ "鏡音リン" => "Kagamine Rin",
66
+ "鏡音レン" => "Kagamine Ren",
67
+ "巡音ルカ" => "Megurine Ruka",
68
+ "KAITO" => "Kaito",
69
+ "MEIKO" => "Meiko",
70
+ "重音テト" => "Kasane Teto",
71
+ "GUMI" => "Gumi",
72
+ "神威がくぽ" => "Kamui Gakupo",
73
+ "VY1" => "VY1",
74
+ "歌愛ユキ" => "Kaai Yuki"}
75
+
76
+ class << self
77
+ def puts_progress(str)
78
+ puts "<bold><blue> *</blue> <white>#{str}</white></bold>".termcolor
79
+ yield
80
+ end
81
+
82
+ def run(argv)
83
+ puts "Usage: #{File.basename(__FILE__)} [config_file=config.yml]" if argv[0] == "--help"
84
+
85
+ config = YAML.load_file(argv[0] || "config.yml")
86
+
87
+ nv = Niconico.new(config["account"]["mail"], config["account"]["password"])
88
+
89
+ ffmpeg = config["ffmpeg"] || "ffmpeg"
90
+
91
+ cache_dir = File.expand_path(config["directories"]["cache"])
92
+ output_dir = File.expand_path(config["directories"]["output"])
93
+ tmpdir = File.expand_path(config["directories"]["temporary"])
94
+
95
+ if File.exist?(tmpdir)
96
+ FileUtils.remove_entry_secure(tmpdir)
97
+ end
98
+ FileUtils.mkdir(tmpdir)
99
+
100
+ converted = []
101
+ if File.exist?(output_dir)
102
+ nicoloid_converted = "#{output_dir}/nicoloid_converted"
103
+
104
+ if File.exist?(nicoloid_converted)
105
+ converted = open(nicoloid_converted,&:readlines).map(&:chomp)
106
+ end
107
+ else
108
+ FileUtils.mkdir output_dir
109
+ end
110
+
111
+ nv.agent.set_proxy(config["proxy"]["host"],config["proxy"]["port"]) if config["proxy"]
112
+
113
+ max = config["limit"] ? config["limit"].to_i : 10
114
+
115
+ puts "<bold><blue>=&gt;</blue> <white>Loading list...</white></bold>".termcolor
116
+
117
+ videos = []
118
+
119
+ case config["source"]["from"]
120
+ when nil, "ranking"
121
+ config["source"]["category"] ||= config["source"]["category"].to_sym \
122
+ || :vocaloid
123
+ %w(method span category).each do |k|
124
+ config["source"][k.to_sym] = config["source"][k].to_sym if config["source"][k]
125
+ end
126
+
127
+ videos = nv.ranking(config["source"]["category"], config["source"])
128
+ when "vocaran"
129
+ latest_vocaran = nv.mylist(9352163)[-1]
130
+ if /(PL|PL) ?[::] ?mylist\/(\d+)/ =~ latest_vocaran.description
131
+ mylist_id = $2
132
+ videos = nv.mylist(mylist_id)
133
+ sleep 1
134
+ else
135
+ warn "<bold><red>=&gt;</red> <white>Failed to detect mylist</white></bold>".termcolor
136
+ end
137
+ else
138
+ warn "WARNING: source name is wrong or not supported. you gave #{config["source"]["from"]} as source name."
139
+ end
140
+
141
+ videos[0...max].each_with_index do |v, i|
142
+ puts "<bold><blue>=&gt;</blue> <white>#{i+1}. (#{v.id}) #{v.title}</white><bold>".termcolor
143
+ begin
144
+ skip_message = "<bold><green> *</green> <white>Skipped</white></bold>".termcolor
145
+ (puts skip_message.termcolor; next) if converted.include?(v.id)
146
+ (puts skip_message; sleep 7; next) if v.type == :swf
147
+
148
+ videoname = "#{cache_dir}/#{v.id}.#{v.type}"
149
+ thumbname = "#{tmpdir}/#{v.id}.jpg"
150
+ cookie_jar = "#{tmpdir}/cookie.txt"
151
+
152
+ video_downloaded = false
153
+ puts_progress "Downloading video" do
154
+ unless Dir["#{cache_dir}/#{v.id}.*"].empty?
155
+ puts "<green> *</green> <white>Using from cache</white>".termcolor
156
+ break
157
+ end
158
+ puts "<bold><red> *</red> <white>Seems economy</white></bold>".termcolor if v.economy?
159
+ if (`curl --help` rescue nil)
160
+ a = v.get_video_by_other
161
+ cookies = a[:cookie]
162
+ url = a[:url]
163
+
164
+ open(cookie_jar, "w") do |io|
165
+ io.puts cookies.map { |cookie|
166
+ [cookie.domain, "TRUE", cookie.path,
167
+ cookie.secure.inspect.upcase, cookie.expires.to_i,
168
+ cookie.name, cookie.value].join("\t")
169
+ }.join("\n")
170
+ end
171
+
172
+ unless system("curl", "-#", "-o", videoname, "-b", cookie_jar, url)
173
+ puts "<bold><red>=&gt;</red> <white>Failed...</white></bold>".termcolor
174
+ end
175
+ else
176
+ puts "<bold><red> *</red> <white>if you have a curl, you can download videos with progress bar.</white></bold>".termcolor
177
+ open(videoname,"wb") do |f|
178
+ f.print v.get_video
179
+ end
180
+ end
181
+ end
182
+ video_downloaded = true
183
+
184
+ filename = nil
185
+ puts_progress "Converting to mp3" do
186
+ #outext = `ffmpeg -i #{videoname} 2>&1`[/^ +Stream.+?: Audio: (.+?),/, 1]
187
+ outext = nil
188
+ basename = "#{i+1}_#{v.id}_#{v.title.gsub(/\//,"-")}.#{outext||"mp3"}"
189
+ filename = "#{output_dir}/#{basename}"
190
+
191
+ cmd = if outext
192
+ [ffmpeg, "-loglevel", "quiet", "-i", videoname, "-acodec", "copy", filename]
193
+ else
194
+ [ffmpeg, "-loglevel", "quiet", "-i", videoname, "-ab", "320k", filename]
195
+ end
196
+ unless system(*cmd)
197
+ puts "<bold><red>=&gt;</red> <white>Failed...</white></bold>".termcolor
198
+ exit 1
199
+ end
200
+ end
201
+
202
+ artists=artist_sorting=nil
203
+ puts_progress "Detecting artists" do
204
+ vt = v.title
205
+
206
+ artists = v.tags.select{|tag| VOCALOIDS.include?(tag) }
207
+
208
+ if artists.empty?
209
+ puts "<green>=&gt;</green> <white>Detection by tags failed. try detecting from the title...</white>".termcolor
210
+ artists = VOCALOIDS.inject([]){|r,i| vt.include?(i) ? r << i : r }
211
+ end
212
+
213
+ artists.map!{|i| VOCALOIDS_ALIAS.key?(i) ? VOCALOIDS_ALIAS[i] : i }
214
+ artists.uniq!
215
+
216
+ artist_sorting = artists.map{|i| VOCALOIDS_SORTING[i] || i}.join(', ')
217
+ artists = artists.join(', ')
218
+
219
+ puts
220
+ puts " #{artists}"
221
+ puts " #{artist_sorting}"
222
+ puts
223
+ end
224
+
225
+ puts_progress "Exporting thumbnail" do
226
+ unless system(ffmpeg, "-loglevel", "quiet", "-i", videoname, *%w(-f image2 -vframes 1 -ss 10 -an -deinterlace), thumbname)
227
+ puts "<bold><red>=&gt;</red> <white>Failed...</white></bold>".termcolor
228
+ exit 1
229
+ end
230
+ end
231
+
232
+ puts_progress "Setting ID3 Tags..." do
233
+ file = TagLib::MPEG::File.new(filename)
234
+ tag = file.id3v2_tag
235
+ tag.artist = artists
236
+ tag.title = v.title
237
+ tag.album = v.title
238
+
239
+ cover = TagLib::ID3v2::AttachedPictureFrame.new
240
+ cover.mime_type = "image/jpeg"
241
+ cover.description = "cover"
242
+ cover.type = TagLib::ID3v2::AttachedPictureFrame::FrontCover
243
+ cover.picture = File.open(thumbname, "rb").read
244
+
245
+ sort = TagLib::ID3v2::TextIdentificationFrame.new("TSOP",TagLib::String::UTF8)
246
+ sort.text = artist_sorting
247
+
248
+ tag.add_frame(cover)
249
+ tag.add_frame(sort)
250
+
251
+ file.save
252
+ end
253
+ rescue Exception => e
254
+ files = [filename,tmpdir]
255
+ files << videoname unless video_downloaded
256
+ files.each do |f|
257
+ FileUtils.remove_entry_secure f if File.exist?(f)
258
+ end
259
+ if e.class == Interrupt
260
+ puts
261
+ puts_progress("Interrupt."){}
262
+ exit
263
+ else
264
+ raise e
265
+ end
266
+ else
267
+ converted << v.id
268
+ open(nicoloid_converted,"w") do |f|
269
+ f.print converted.join("\n")
270
+ end
271
+ end
272
+
273
+ puts_progress "Wait..." do
274
+ 5.times {print "."; sleep 1}
275
+ puts
276
+ puts
277
+ end
278
+ end
279
+
280
+ puts_progress "Removing temporary directory" do
281
+ FileUtils.remove_entry_secure tmpdir
282
+ end
283
+ end
284
+ end
285
+ end
286
+
@@ -0,0 +1,3 @@
1
+ module Nicoloid
2
+ VERSION = "1.0.0"
3
+ end
data/nicoloid.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "nicoloid/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "nicoloid"
7
+ s.version = Nicoloid::VERSION
8
+ s.authors = ["Shota Fukumori (sora_h)"]
9
+ s.email = ["sorah@tubusu.net"]
10
+ s.homepage = ""
11
+ s.summary = "Download video from nicovideo and convert to mp3"
12
+ s.description = "nicoloid downloads video from nicovideo.jp, and convert videos to mp3 using ffmpeg."
13
+
14
+ s.rubyforge_project = "nicoloid"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+ end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nicoloid
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Shota Fukumori (sora_h)
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-17 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: nicoloid downloads video from nicovideo.jp, and convert videos to mp3
15
+ using ffmpeg.
16
+ email:
17
+ - sorah@tubusu.net
18
+ executables:
19
+ - nicoloid
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - .gitignore
24
+ - Gemfile
25
+ - README.mkd
26
+ - Rakefile
27
+ - bin/nicoloid
28
+ - lib/nicoloid.rb
29
+ - lib/nicoloid/version.rb
30
+ - nicoloid.gemspec
31
+ homepage: ''
32
+ licenses: []
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project: nicoloid
51
+ rubygems_version: 1.8.11
52
+ signing_key:
53
+ specification_version: 3
54
+ summary: Download video from nicovideo and convert to mp3
55
+ test_files: []
56
+ has_rdoc: