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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5f8b27af310126a64b577f8bc0720f7b26b2dd06
4
- data.tar.gz: 7cd30e5c8111192be2c391e2051c234061dec6f3
3
+ metadata.gz: c5f0c8bd1b296caf18b4fcce67f896e3349b2ff4
4
+ data.tar.gz: 2cf890bcaf3da97043709f15940ffdc986e53817
5
5
  SHA512:
6
- metadata.gz: 0a7051e1beefe24355ef142acdb43557810cc88e561d9268c0b030556f1aa7aef219068b1e41428aa5ffa1d2e2370ff211ac51633adaf4a8d44e74fd5d7b15e5
7
- data.tar.gz: eb829204f102156b78306425e3cff1d4a71de1b319438a38d1dc61aa069dd80c462823237e451cb38e6f2a057d2496d4ba106d54383e3f6a971311c2f491f023
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 __$HOME/.config/nv__
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
- Also you can use more easy way.
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
@@ -3,4 +3,9 @@
3
3
 
4
4
  require 'nv'
5
5
 
6
- Nv::CLI.start(ARGV)
6
+ begin
7
+ Nv::CLI.start(ARGV)
8
+ rescue SystemExit, Interrupt
9
+ rescue Exception => e
10
+ puts e
11
+ end
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 = File.join(ENV['HOME'], '.config', 'nv')
24
+ CONFIG_PATH = "#{ENV['HOME']}/.config/nv"
37
25
  end
@@ -3,7 +3,10 @@ require 'thor'
3
3
  class Nv::CLI < Thor
4
4
  include Niconico::Helper
5
5
 
6
- desc "dl URL", "Download video"
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
- # Donwload
29
- video.download
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 "info URL", "Show video/mylist info"
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 "=" * 40
64
+ puts '=' * 40
56
65
  puts video.description
57
- puts "=" * 40
66
+ puts '=' * 40
58
67
  puts "URL: #{video.watch_url}"
59
68
  end
60
69
  end
61
70
 
62
- desc "config KEY VALUE", "Set config"
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 " #{k}=#{v}"
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: #{key}=#{config[key]}"
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
@@ -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.stringify_keys)
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
@@ -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
- $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
11
-
12
- require 'niconico/helper'
13
- require 'niconico/fabric'
14
- require 'niconico/base'
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
@@ -4,5 +4,9 @@ module Niconico
4
4
  return true if url =~ /mylist\/\d+/
5
5
  false
6
6
  end
7
+
8
+ def escape_string(str)
9
+ str.gsub(/[\/\\?*:|><]/) {|m| [m.ord + 65248].pack('U*')}
10
+ end
7
11
  end
8
12
  end
@@ -22,7 +22,7 @@ module Niconico
22
22
  end
23
23
 
24
24
  def fetch
25
- doc = REXML::Document.new(@agent.get("http://www.nicovideo.jp/mylist/#{@id}?rss=2.0").body)
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
  })
@@ -11,32 +11,118 @@ module Niconico
11
11
  end
12
12
 
13
13
  def download(output=".")
14
- escapedTitle = thumb.title.gsub(/\//, "/")
15
- filename = "#{escapedTitle} - [#{thumb.video_id}].#{thumb.extension}"
16
- filepath = File.join(output, filename)
14
+ escaped_title = escape_string(thumb.title)
15
+ escaped_output = escape_string(output)
17
16
 
18
- Dir.mkdir(output) unless Dir.exist? output
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
- File.open(filepath, 'wb') do |fp|
22
- open(flv.url, 'rb',
23
- 'Cookie' => flv.history_cookies,
24
- :content_length_proc => lambda{ |content_length|
25
- if content_length
26
- progress_bar = ProgressBar.create(:total => content_length)
27
- end
28
- },
29
- :progress_proc => lambda{ |transferred_bytes|
30
- if progress_bar
31
- progress_bar.progress = transferred_bytes
32
- else
33
- puts "#{transferred_bytes} / Total size is unknown"
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
 
@@ -1,3 +1,3 @@
1
1
  module Nv
2
- VERSION = "1.0.1"
2
+ VERSION = "1.2.1"
3
3
  end
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.0.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-30 00:00:00.000000000 Z
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