nv 1.0.1 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +17 -2
- data/bin/nv +6 -1
- data/lib/nv.rb +1 -13
- data/lib/nv/cli.rb +32 -11
- data/lib/nv/config.rb +11 -2
- data/lib/nv/niconico.rb +7 -8
- data/lib/nv/niconico/helper.rb +4 -0
- data/lib/nv/niconico/mylist.rb +9 -9
- data/lib/nv/niconico/video.rb +106 -21
- data/lib/nv/version.rb +1 -1
- data/nv.gemspec +0 -1
- metadata +2 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5f0c8bd1b296caf18b4fcce67f896e3349b2ff4
|
4
|
+
data.tar.gz: 2cf890bcaf3da97043709f15940ffdc986e53817
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9769a36ba372b6457831268ca13e2145db62b5fd502744d0012d7c7d158e0fc284745ec87bffc95bd9854bcb3ef84335b8c26eecda51e081ba7ecc12e349cb6
|
7
|
+
data.tar.gz: dc112b9d3c8909c694c732e6c9e17d077557be2090386414c460e84f1485f21b42cc84bf5c3d175172e1a58058952644c53c5d7574ef9040b8672c06d865d92b
|
data/README.md
CHANGED
@@ -17,7 +17,7 @@ $ nv config email john@example.com
|
|
17
17
|
$ nv config password pAsSwoRd
|
18
18
|
```
|
19
19
|
|
20
|
-
Default config file will be put on __
|
20
|
+
Default config file will be put on __~/.config/nv__
|
21
21
|
|
22
22
|
### Download
|
23
23
|
|
@@ -26,13 +26,28 @@ $ nv dl http://www.nicovideo.jp/watch/sm22538737
|
|
26
26
|
$ nv dl http://www.nicovideo.jp/mylist/33435425
|
27
27
|
```
|
28
28
|
|
29
|
-
|
29
|
+
You also can use more shorten addresses.
|
30
30
|
|
31
31
|
```session
|
32
32
|
$ nv dl sm9
|
33
33
|
$ nv dl mylist/33435425
|
34
34
|
```
|
35
35
|
|
36
|
+
#### Options
|
37
|
+
|
38
|
+
##### Directory
|
39
|
+
|
40
|
+
```session
|
41
|
+
$ nv dl sm9 --with-dir
|
42
|
+
$ nv dl mylist/33435425 --without-dir
|
43
|
+
```
|
44
|
+
|
45
|
+
##### Comments
|
46
|
+
|
47
|
+
```session
|
48
|
+
$ nv dl sm9 --with-comments
|
49
|
+
```
|
50
|
+
|
36
51
|
### Audit
|
37
52
|
|
38
53
|
```session
|
data/bin/nv
CHANGED
data/lib/nv.rb
CHANGED
@@ -5,18 +5,6 @@ require "nv/cli"
|
|
5
5
|
|
6
6
|
=begin
|
7
7
|
|
8
|
-
nico = Niconico.new.sign_in(...)
|
9
|
-
video = nico.video('sm9')
|
10
|
-
video.download('./')
|
11
|
-
|
12
|
-
mylist = nico.mylist('482029')
|
13
|
-
mylist.download()
|
14
|
-
|
15
|
-
include Niconico::Helper
|
16
|
-
if mylist? 'http://...'
|
17
|
-
...
|
18
|
-
end
|
19
|
-
|
20
8
|
##### Way #####
|
21
9
|
|
22
10
|
1. nico = Niconico::Base.new.sign_in(...)
|
@@ -33,5 +21,5 @@ end
|
|
33
21
|
module Nv
|
34
22
|
class LackOfInformation < StandardError; end
|
35
23
|
|
36
|
-
CONFIG_PATH =
|
24
|
+
CONFIG_PATH = "#{ENV['HOME']}/.config/nv"
|
37
25
|
end
|
data/lib/nv/cli.rb
CHANGED
@@ -3,7 +3,10 @@ require 'thor'
|
|
3
3
|
class Nv::CLI < Thor
|
4
4
|
include Niconico::Helper
|
5
5
|
|
6
|
-
desc
|
6
|
+
desc 'dl URL', 'Download video'
|
7
|
+
method_option 'with-comments', :aliases => '-c', :desc => 'Download comments'
|
8
|
+
method_option 'with-dir', :aliases => '-d', :desc => 'Create directory'
|
9
|
+
method_option 'without-dir', :aliases => '-D', :desc => "Don't create directory"
|
7
10
|
def dl(ptr, output=".")
|
8
11
|
config = Nv::Config.new(Nv::CONFIG_PATH)
|
9
12
|
config.verify_for_authentication!('dl')
|
@@ -14,7 +17,10 @@ class Nv::CLI < Thor
|
|
14
17
|
mylist = nico.mylist(ptr)
|
15
18
|
|
16
19
|
puts "Title : #{mylist.title}"
|
17
|
-
puts "Desc : #{mylist.description}"
|
20
|
+
puts "Desc : #{mylist.description}" unless mylist.description.empty?
|
21
|
+
|
22
|
+
escaped_title = escape_string(mylist.title)
|
23
|
+
output = options['without-dir'] ? '.' : escaped_title
|
18
24
|
|
19
25
|
mylist.items.each do |item|
|
20
26
|
dl(item.link, output)
|
@@ -25,14 +31,17 @@ class Nv::CLI < Thor
|
|
25
31
|
# Inspect
|
26
32
|
puts "Downloading... #{video.title}"
|
27
33
|
|
28
|
-
|
29
|
-
|
34
|
+
output ||= options['with-dir'] ? escape_string(video.title) : '.'
|
35
|
+
|
36
|
+
# Download
|
37
|
+
video.download output
|
38
|
+
video.download_comments output if options['with-comments']
|
30
39
|
|
31
40
|
puts "+ done"
|
32
41
|
end
|
33
42
|
end
|
34
43
|
|
35
|
-
desc
|
44
|
+
desc 'info URL', 'Show video/mylist info'
|
36
45
|
def info(ptr)
|
37
46
|
config = Nv::Config.new(Nv::CONFIG_PATH)
|
38
47
|
config.verify_for_authentication!('info')
|
@@ -52,21 +61,27 @@ class Nv::CLI < Thor
|
|
52
61
|
video = nico.video(ptr)
|
53
62
|
|
54
63
|
puts video.title
|
55
|
-
puts
|
64
|
+
puts '=' * 40
|
56
65
|
puts video.description
|
57
|
-
puts
|
66
|
+
puts '=' * 40
|
58
67
|
puts "URL: #{video.watch_url}"
|
59
68
|
end
|
60
69
|
end
|
61
70
|
|
62
|
-
desc
|
71
|
+
desc 'browse FILE', 'Open web-browser to show nicovideo page with given movie file'
|
72
|
+
def browse(filepath)
|
73
|
+
video_id = File.basename(filepath).match(/[^\w]([\w]{2}\d+)[^\w]/)[1]
|
74
|
+
system "open http://www.nicovideo.jp/watch/#{video_id}"
|
75
|
+
end
|
76
|
+
|
77
|
+
desc 'config KEY VALUE', 'Set config'
|
63
78
|
def config(key=nil, value=nil)
|
64
79
|
config = Nv::Config.new(Nv::CONFIG_PATH)
|
65
80
|
|
66
81
|
unless key
|
67
|
-
puts "config
|
82
|
+
puts "=== config(#{Nv::CONFIG_PATH}) ==="
|
68
83
|
config.to_h.each do |k, v|
|
69
|
-
puts "
|
84
|
+
puts "#{k}=#{v}"
|
70
85
|
end
|
71
86
|
return
|
72
87
|
end
|
@@ -76,6 +91,12 @@ class Nv::CLI < Thor
|
|
76
91
|
config.save
|
77
92
|
end
|
78
93
|
|
79
|
-
puts "config
|
94
|
+
puts "=== config(#{Nv::CONFIG_PATH}) ==="
|
95
|
+
puts "#{key}=#{config[key]}"
|
96
|
+
end
|
97
|
+
|
98
|
+
desc "version", "Show version"
|
99
|
+
def version
|
100
|
+
puts "nv version #{Nv::VERSION}"
|
80
101
|
end
|
81
102
|
end
|
data/lib/nv/config.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'ostruct'
|
2
2
|
require 'yaml'
|
3
3
|
require 'fileutils'
|
4
|
-
require 'active_support/core_ext'
|
5
4
|
|
6
5
|
class String
|
7
6
|
def undent
|
@@ -25,7 +24,7 @@ module Nv
|
|
25
24
|
|
26
25
|
def save
|
27
26
|
File.open(@config_path, 'w') do |f|
|
28
|
-
f.print YAML.dump(self.to_h.
|
27
|
+
f.print YAML.dump(transform_keys(self.to_h){|k| k.to_s})
|
29
28
|
end
|
30
29
|
end
|
31
30
|
|
@@ -43,5 +42,15 @@ module Nv
|
|
43
42
|
exit
|
44
43
|
end
|
45
44
|
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def transform_keys(hs)
|
49
|
+
result = {}
|
50
|
+
hs.each_key do |key|
|
51
|
+
result[yield(key)] = hs[key]
|
52
|
+
end
|
53
|
+
result
|
54
|
+
end
|
46
55
|
end
|
47
56
|
end
|
data/lib/nv/niconico.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'mechanize'
|
2
2
|
require 'open-uri'
|
3
|
+
require 'net/http'
|
3
4
|
require 'uri'
|
4
5
|
require 'cgi'
|
5
6
|
require 'rexml/document'
|
@@ -7,14 +8,12 @@ require 'rss'
|
|
7
8
|
require 'ostruct'
|
8
9
|
require 'ruby-progressbar'
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
require 'niconico/
|
13
|
-
require 'niconico/
|
14
|
-
require 'niconico/
|
15
|
-
require 'niconico/video'
|
16
|
-
require 'niconico/mylist'
|
11
|
+
require 'nv/niconico/helper'
|
12
|
+
require 'nv/niconico/fabric'
|
13
|
+
require 'nv/niconico/base'
|
14
|
+
require 'nv/niconico/video'
|
15
|
+
require 'nv/niconico/mylist'
|
17
16
|
|
18
17
|
module Niconico
|
19
|
-
|
18
|
+
OUTPUT_NAME = "%{title} - [%{id}].%{extension}"
|
20
19
|
end
|
data/lib/nv/niconico/helper.rb
CHANGED
data/lib/nv/niconico/mylist.rb
CHANGED
@@ -22,7 +22,7 @@ module Niconico
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def fetch
|
25
|
-
doc = REXML::Document.new(
|
25
|
+
doc = REXML::Document.new(open("http://www.nicovideo.jp/mylist/#{@id}?rss=2.0").read)
|
26
26
|
|
27
27
|
channel = doc.elements['/rss/channel']
|
28
28
|
|
@@ -42,14 +42,14 @@ module Niconico
|
|
42
42
|
end
|
43
43
|
|
44
44
|
@mylist = OpenStruct.new({
|
45
|
-
:title => channel.elements['title/text()'],
|
46
|
-
:link => channel.elements['link/text()'],
|
47
|
-
:description => channel.elements['description/text()'],
|
48
|
-
:created_at => channel.elements['pubDate/text()'],
|
49
|
-
:updated_at => channel.elements['lastBuildDate/text()'],
|
50
|
-
:generator => channel.elements['generator/text()'],
|
51
|
-
:author => channel.elements['dc:creator/text()'],
|
52
|
-
:language => channel.elements['language/text()'],
|
45
|
+
:title => channel.elements['title/text()'].to_s.gsub(/(^マイリスト\s|‐ニコニコ動画$)/, ''),
|
46
|
+
:link => channel.elements['link/text()'].to_s,
|
47
|
+
:description => channel.elements['description/text()'].to_s,
|
48
|
+
:created_at => channel.elements['pubDate/text()'].to_s,
|
49
|
+
:updated_at => channel.elements['lastBuildDate/text()'].to_s,
|
50
|
+
:generator => channel.elements['generator/text()'].to_s,
|
51
|
+
:author => channel.elements['dc:creator/text()'].to_s,
|
52
|
+
:language => channel.elements['language/text()'].to_s,
|
53
53
|
:items => items,
|
54
54
|
:items_count => items.size
|
55
55
|
})
|
data/lib/nv/niconico/video.rb
CHANGED
@@ -11,32 +11,118 @@ module Niconico
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def download(output=".")
|
14
|
-
|
15
|
-
|
16
|
-
filepath = File.join(output, filename)
|
14
|
+
escaped_title = escape_string(thumb.title)
|
15
|
+
escaped_output = escape_string(output)
|
17
16
|
|
18
|
-
|
17
|
+
filename = sprintf OUTPUT_NAME, {:title => escaped_title, :id => thumb.video_id, :extension => thumb.extension}
|
18
|
+
filepath = File.join(escaped_output, filename)
|
19
|
+
filepath_nvdownload = "#{filepath}.nvdownload"
|
19
20
|
|
21
|
+
# Return when video file is already exist
|
22
|
+
if File.exist? filepath
|
23
|
+
File.delete filepath_nvdownload if File.exist? filepath_nvdownload
|
24
|
+
return
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create output dir
|
28
|
+
Dir.mkdir escaped_output unless Dir.exist? escaped_output
|
29
|
+
|
30
|
+
# Define request headers
|
31
|
+
options = {
|
32
|
+
'Cookie' => flv.history_cookies
|
33
|
+
}
|
34
|
+
if File.exist? filepath_nvdownload
|
35
|
+
options['Range'] = "bytes=#{File.size(filepath_nvdownload)}-"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Download video
|
20
39
|
progress_bar = nil
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
40
|
+
url = URI.parse(flv.url)
|
41
|
+
begin
|
42
|
+
Net::HTTP.start(url.host, url.port) do |http|
|
43
|
+
header = http.request_head("#{url.path}?#{url.query}", options)
|
44
|
+
progress_bar = ProgressBar.create(:total => header['content-length'].to_i)
|
45
|
+
transferred_bytes = 0
|
46
|
+
request = Net::HTTP::Get.new(url, options)
|
47
|
+
http.request request do |response|
|
48
|
+
open(filepath_nvdownload, 'ab') do |io|
|
49
|
+
response.read_body do |chunk|
|
50
|
+
transferred_bytes += chunk.size
|
51
|
+
if progress_bar
|
52
|
+
progress_bar.progress = transferred_bytes
|
53
|
+
else
|
54
|
+
puts "#{transferred_bytes} / Total size is unknown"
|
55
|
+
end
|
56
|
+
|
57
|
+
io.write chunk
|
58
|
+
end
|
34
59
|
end
|
35
|
-
|
36
|
-
) do |f|
|
37
|
-
fp.print f.read
|
60
|
+
end
|
38
61
|
end
|
62
|
+
rescue => e
|
63
|
+
puts "Failed download: #{e}"
|
64
|
+
return
|
65
|
+
end
|
66
|
+
|
67
|
+
# Rename .nvdownload to real file
|
68
|
+
File.rename(filepath_nvdownload, filepath)
|
69
|
+
end
|
70
|
+
|
71
|
+
# GET http://flapi.nicovideo.jp/api/getwaybackkey?thread=1345476375
|
72
|
+
# => waybackkey=1417346808.E9d0LUF9gvFvt3Rrf5TP91Pa0LA
|
73
|
+
|
74
|
+
# POST http://msg.nicovideo.jp/53/api/
|
75
|
+
# <packet><thread thread="1345476375" version="20090904" user_id="1501297" scores="1" nicoru="1" with_global="1"/><thread_leaves thread="1345476375" user_id="1501297" scores="1" nicoru="1">0-14:100,1000</thread_leaves></packet>
|
76
|
+
# <packet>
|
77
|
+
# <thread thread="1345476375"
|
78
|
+
# version="20090904"
|
79
|
+
# waybackkey="1417346808.E9d0LUF9gvFvt3Rrf5TP91Pa0LA"
|
80
|
+
# when="1417346804"
|
81
|
+
# user_id="1501297"
|
82
|
+
# scores="1"
|
83
|
+
# nicoru="1"
|
84
|
+
# />
|
85
|
+
# <thread_leaves
|
86
|
+
# thread="1345476375"
|
87
|
+
# waybackkey="1417346808.E9d0LUF9gvFvt3Rrf5TP91Pa0LA"
|
88
|
+
# when="1417346804" # 起点
|
89
|
+
# user_id="1501297"
|
90
|
+
# res_before="8541"
|
91
|
+
# scores="1"
|
92
|
+
# nicoru="1" >0-14:100,1000</thread_leaves>
|
93
|
+
# </packet>
|
94
|
+
# <chat thread="1345476375" no="8540" vpos="55658" date="1417346426" mail="184" user_id="tzaiW5hp-SvJG6UGkEa0kELQd3w" anonymity="1" leaf="9">白いレースのハンカチかな?</chat>
|
95
|
+
# <chat thread="1345476375" no="8539" vpos="41534" date="1417233687" mail="184" user_id="1p_4U9fr-YvliRaUl3E6XGEavp4" premium="1" anonymity="1" leaf="6">くっそwwww</chat>
|
96
|
+
def download_comments(output=".")
|
97
|
+
escaped_title = escape_string(thumb.title)
|
98
|
+
escaped_output = escape_string(output)
|
99
|
+
|
100
|
+
filename = sprintf OUTPUT_NAME, {:title => escaped_title, :id => thumb.video_id, :extension => 'comments'}
|
101
|
+
filepath = File.join(escaped_output, filename)
|
102
|
+
|
103
|
+
Dir.mkdir(escaped_output) unless Dir.exist? escaped_output
|
104
|
+
|
105
|
+
url = URI.parse(flv.ms)
|
106
|
+
|
107
|
+
thread_id = flv.thread_id
|
108
|
+
length = (flv.l.to_i / 60).round
|
109
|
+
res = Net::HTTP.new(url.host).start do |http|
|
110
|
+
req = Net::HTTP::Post.new(url.path, {'Cookie' => flv.history_cookies})
|
111
|
+
req.body = %|<packet><thread thread="#{thread_id}" version="20090904" scores="1" nicoru="1" with_global="1"/><thread_leaves thread="#{thread_id}" scores="1" nicoru="1">0-#{length}:10</thread_leaves></packet>|
|
112
|
+
http.request(req)
|
39
113
|
end
|
114
|
+
|
115
|
+
open(filepath, 'w') do |f|
|
116
|
+
f.write res.body
|
117
|
+
end
|
118
|
+
|
119
|
+
# TODO: Comment parser
|
120
|
+
# doc = REXML::Document.new(res.body)
|
121
|
+
# chats = doc.elements.to_a('/packet/chat')
|
122
|
+
# chats.each do |chat|
|
123
|
+
# puts chat.attribute('vpos')
|
124
|
+
# puts chat.text
|
125
|
+
# end
|
40
126
|
end
|
41
127
|
|
42
128
|
# Combined parameter fetcher
|
@@ -78,7 +164,6 @@ module Niconico
|
|
78
164
|
|
79
165
|
def flv(id=@id)
|
80
166
|
return @flv if @flv
|
81
|
-
|
82
167
|
@agent.get("http://www.nicovideo.jp/watch/#{id}")
|
83
168
|
history_cookie = @agent.cookies.map(&:to_s).join('; ')
|
84
169
|
|
data/lib/nv/version.rb
CHANGED
data/nv.gemspec
CHANGED
@@ -21,7 +21,6 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.7"
|
22
22
|
spec.add_development_dependency "rake", "~> 10.0"
|
23
23
|
|
24
|
-
spec.add_dependency "activesupport"
|
25
24
|
spec.add_dependency "mechanize"
|
26
25
|
spec.add_dependency "thor"
|
27
26
|
spec.add_dependency "ruby-progressbar"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yasuaki Uechi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,20 +38,6 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: activesupport
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
42
|
name: mechanize
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|