nv 1.0.1 → 1.2.1
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/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
|