nv 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 34a85a4316b10f3de92c6280c366311795358446
4
+ data.tar.gz: f3ad31ade0fbb1988fa2975c3781c2a3a197db88
5
+ SHA512:
6
+ metadata.gz: 6d98bbcceea4386e9435c4dc184c1aa1ffafd90f91f824748d127d1e2d6d4a39b2584da2a551b95a66467dffa75f9059ba574c4fb9367d7e0285af24950d99af
7
+ data.tar.gz: 77dacada776466f7db59370ab071aad84eecb625e033dde988fccffcd459fedd991be0d18ae53e41a80bf43bf54031748637ab49bced5ec558f0a507f0663737
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ Gemfile.lock
2
+ /.bundle
3
+ /vendor/bundle
4
+ /pkg
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nv.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Yasuaki Uechi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # nv
2
+
3
+ The commandline tool for downloading videos and mylist at nicovideo.
4
+
5
+ ## Installation
6
+
7
+ ```session
8
+ $ gem install nv
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Setup
14
+
15
+ ```session
16
+ $ nv config email john@example.com
17
+ $ nv config password pAsSwoRd
18
+ ```
19
+
20
+ ### Download
21
+
22
+ ```session
23
+ $ nv dl http://www.nicovideo.jp/watch/sm22538737
24
+ $ nv dl http://www.nicovideo.jp/mylist/33435425
25
+ ```
26
+
27
+ Also you can use more easy way.
28
+
29
+ ```session
30
+ $ nv dl sm9
31
+ $ nv dl mylist/33435425
32
+ ```
33
+
34
+ ### Audit
35
+
36
+ ```session
37
+ $ nv info sm9
38
+ $ nv info mylist/33435425
39
+ ```
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/nv ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'nv'
5
+
6
+ Nv::CLI.start(ARGV)
data/lib/nv.rb ADDED
@@ -0,0 +1,37 @@
1
+ require "nv/version"
2
+ require "nv/config"
3
+ require "nv/niconico"
4
+ require "nv/cli"
5
+
6
+ =begin
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
+ ##### Way #####
21
+
22
+ 1. nico = Niconico::Base.new.sign_in(...)
23
+ video = nico.video('sm9') => Niconico::Video
24
+ puts video.id
25
+ video.download
26
+
27
+ 2. video = Niconico::Video.new('sm9')
28
+ video.sign_in(...)
29
+ video.download
30
+
31
+ =end
32
+
33
+ module Nv
34
+ class LackOfInformation < StandardError; end
35
+
36
+ CONFIG_PATH = File.join(ENV['HOME'], '.config', 'nv')
37
+ end
data/lib/nv/cli.rb ADDED
@@ -0,0 +1,81 @@
1
+ require 'thor'
2
+
3
+ class Nv::CLI < Thor
4
+ include ::Niconico::Helper
5
+
6
+ desc "dl URL", "Download video"
7
+ def dl(ptr, output=".")
8
+ config = Nv::Config.new(Nv::CONFIG_PATH)
9
+ config.verify_for_authentication!('dl')
10
+
11
+ nico = Niconico::Base.new.sign_in(config.email, config.password)
12
+
13
+ if mylist?(ptr)
14
+ mylist = nico.mylist(ptr)
15
+
16
+ puts "Title : #{mylist.title}"
17
+ puts "Desc : #{mylist.description}"
18
+
19
+ mylist.items.each do |item|
20
+ dl(item.link, output)
21
+ end
22
+ else
23
+ video = nico.video(ptr)
24
+
25
+ # Inspect
26
+ puts "Downloading... #{video.title}"
27
+
28
+ # Donwload
29
+ video.download
30
+
31
+ puts "+ done"
32
+ end
33
+ end
34
+
35
+ desc "info URL", "Show video/mylist info"
36
+ def info(ptr)
37
+ config = Nv::Config.new(Nv::CONFIG_PATH)
38
+ config.verify_for_authentication!('info')
39
+
40
+ nico = Niconico::Base.new.sign_in(config.email, config.password)
41
+
42
+ if mylist?(ptr)
43
+ mylist = nico.mylist(ptr)
44
+
45
+ puts "Title : #{mylist.title}"
46
+ puts "Desc : #{mylist.description}"
47
+
48
+ mylist.items.each_with_index do |item, i|
49
+ puts " #{i+1}. #{item.title}"
50
+ end
51
+ else
52
+ video = nico.video(ptr)
53
+
54
+ puts video.title
55
+ puts "=" * 40
56
+ puts video.description
57
+ puts "=" * 40
58
+ puts "URL: #{video.watch_url}"
59
+ end
60
+ end
61
+
62
+ desc "config KEY VALUE", "Set config"
63
+ def config(key=nil, value=nil)
64
+ config = Nv::Config.new(Nv::CONFIG_PATH)
65
+
66
+ unless key
67
+ puts "config:"
68
+ config.to_h.each do |k, v|
69
+ puts " #{k}=#{v}"
70
+ end
71
+ return
72
+ end
73
+
74
+ if value
75
+ config[key] = value
76
+ config.save
77
+ end
78
+
79
+ puts "config: #{key}=#{config[key]}"
80
+ end
81
+ end
data/lib/nv/config.rb ADDED
@@ -0,0 +1,47 @@
1
+ require 'ostruct'
2
+ require 'yaml'
3
+ require 'fileutils'
4
+ require 'active_support/core_ext'
5
+
6
+ class String
7
+ def undent
8
+ gsub(/^.{#{slice(/^ +/).length}}/, '')
9
+ end
10
+ end
11
+
12
+ module Nv
13
+ class Config < OpenStruct
14
+ def initialize(config_path)
15
+ # Initialize config file
16
+ @config_path = config_path
17
+ config_dir = File.dirname(@config_path)
18
+
19
+ Dir.mkdir(config_dir) unless Dir.exist?(config_dir)
20
+ FileUtils.touch(@config_path) unless File.exist?(@config_path)
21
+
22
+ @config = YAML.load_file(@config_path) || {}
23
+ super(@config)
24
+ end
25
+
26
+ def save
27
+ File.open(@config_path, 'w') do |f|
28
+ f.print YAML.dump(self.to_h.stringify_keys)
29
+ end
30
+ end
31
+
32
+ def verify_for_authentication
33
+ self.email && self.password
34
+ end
35
+
36
+ def verify_for_authentication!(cmd)
37
+ unless verify_for_authentication
38
+ puts <<-EOD.undent
39
+ `nv #{cmd}` should be given email and password.
40
+ $ nv config email <email>
41
+ $ nv config password <password>
42
+ EOD
43
+ exit
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,18 @@
1
+ require 'mechanize'
2
+ require 'open-uri'
3
+ require 'uri'
4
+ require 'cgi'
5
+ require 'rexml/document'
6
+ require 'rss'
7
+ require 'ostruct'
8
+ require 'ruby-progressbar'
9
+
10
+ require 'niconico/helper'
11
+ require 'niconico/fabric'
12
+ require 'niconico/base'
13
+ require 'niconico/video'
14
+ require 'niconico/mylist'
15
+
16
+ module Niconico
17
+
18
+ end
@@ -0,0 +1,11 @@
1
+ module Niconico
2
+ class Base < Fabric
3
+ def video(video_id)
4
+ Niconico::Video.new(video_id, @agent)
5
+ end
6
+
7
+ def mylist(mylist_id)
8
+ Niconico::Mylist.new(mylist_id, @agent)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ module Niconico
2
+ class Fabric
3
+ attr_reader :agent
4
+
5
+ def initialize(agent=nil)
6
+ @agent = agent || Mechanize.new
7
+ @agent.verify_mode = OpenSSL::SSL::VERIFY_NONE
8
+ end
9
+
10
+ def sign_in(email, password)
11
+ @agent.post(
12
+ "https://secure.nicovideo.jp/secure/login?site=niconico",
13
+ "mail" => email,
14
+ "password" => password
15
+ )
16
+ return self
17
+ end
18
+
19
+ def signed_in?
20
+ @agent.cookies.any? {|c| c.name == 'user_session'}
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,8 @@
1
+ module Niconico
2
+ module Helper
3
+ def mylist?(url)
4
+ return true if url =~ /mylist\/\d+/
5
+ false
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,58 @@
1
+ module Niconico
2
+ class Mylist < Fabric
3
+ include Niconico::Helper
4
+
5
+ def initialize(ptr, agent=nil)
6
+ super(agent)
7
+
8
+ @id = normalize(ptr)
9
+ @mylist = nil
10
+ fetch
11
+ end
12
+
13
+ def method_missing(method, *args)
14
+ raise(NoMethodError, method) unless @mylist.respond_to? method
15
+ @mylist[method]
16
+ end
17
+
18
+ private
19
+
20
+ def normalize(ptr)
21
+ ptr.match(/mylist\/([0-9]+)\??/)[1]
22
+ end
23
+
24
+ def fetch
25
+ doc = REXML::Document.new(@agent.get("http://www.nicovideo.jp/mylist/#{@id}?rss=2.0").body)
26
+
27
+ channel = doc.elements['/rss/channel']
28
+
29
+ items = []
30
+ channel.elements.each('item') do |item|
31
+ html_description = item.elements['description/text()'].to_s.gsub(/<p class=\"nico-info\">.+<\/p>/, '')
32
+ description = html_description.gsub(/<\/?.*?>/, '')
33
+
34
+ items << OpenStruct.new({
35
+ :title => item.elements['title/text()'].to_s,
36
+ :link => item.elements['link/text()'].to_s,
37
+ :guid => item.elements['guid/text()'].to_s,
38
+ :created_at => item.elements['pubDate/text()'].to_s,
39
+ :description => description,
40
+ :html_description => html_description
41
+ })
42
+ end
43
+
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()'],
53
+ :items => items,
54
+ :items_count => items.size
55
+ })
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,91 @@
1
+ module Niconico
2
+ class Video < Fabric
3
+ include Niconico::Helper
4
+
5
+ def initialize(ptr, agent=nil)
6
+ super(agent)
7
+
8
+ @thumb = nil
9
+ @flv = nil
10
+ @id = normalize(ptr) # pvid | thumb_cached
11
+ end
12
+
13
+ def download(output=".")
14
+ escapedTitle = thumb.title.gsub(/\//, "/")
15
+ filename = "#{escapedTitle} - [#{thumb.video_id}].#{thumb.extension}"
16
+ filepath = File.join(output, filename)
17
+
18
+ Dir.mkdir(output) unless Dir.exist? output
19
+
20
+ 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"
34
+ end
35
+ }
36
+ ) do |f|
37
+ fp.print f.read
38
+ end
39
+ end
40
+ end
41
+
42
+ # Combined parameter fetcher
43
+ def method_missing(method, *args)
44
+ thumb[method] || flv[method] || raise(NoMethodError, method)
45
+ end
46
+
47
+ private
48
+
49
+ def strip_id(url)
50
+ url.match(/(?:watch\/)?(\w{2}?\d+)/)[1]
51
+ end
52
+
53
+ def normalize(ptr)
54
+ vid = strip_id(ptr)
55
+ thumb(vid).perm_video_id unless vid =~ /\A\d+\z/
56
+ end
57
+
58
+ def id
59
+ @id
60
+ end
61
+
62
+ def thumb(id=@id)
63
+ return @thumb if @thumb
64
+
65
+ doc = REXML::Document.new(open("http://ext.nicovideo.jp/api/getthumbinfo/#{id}"))
66
+ watch_url = doc.elements['nicovideo_thumb_response/thumb/watch_url'].text.to_s
67
+ perm_video_id = strip_id(watch_url)
68
+
69
+ @thumb = OpenStruct.new({
70
+ :video_id => doc.elements['nicovideo_thumb_response/thumb/video_id'].text.to_s,
71
+ :perm_video_id => perm_video_id,
72
+ :watch_url => watch_url,
73
+ :extension => doc.elements['nicovideo_thumb_response/thumb/movie_type'].text.to_s,
74
+ :title => doc.elements['nicovideo_thumb_response/thumb/title'].text.to_s,
75
+ :description => doc.elements['nicovideo_thumb_response/thumb/description'].text.to_s
76
+ })
77
+ end
78
+
79
+ def flv(id=@id)
80
+ return @flv if @flv
81
+
82
+ @agent.get("http://www.nicovideo.jp/watch/#{id}")
83
+ history_cookie = @agent.cookies.map(&:to_s).join('; ')
84
+
85
+ flv_str = @agent.get("http://www.nicovideo.jp/api/getflv?v=#{id}").body
86
+ flv_hash = Hash[flv_str.split("&").map{|e| i=e.split('=');i[1]=CGI.unescape(i[1]);i }]
87
+ flv_hash.update(:history_cookies => history_cookie)
88
+ @flv = OpenStruct.new(flv_hash)
89
+ end
90
+ end
91
+ end
data/lib/nv/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Nv
2
+ VERSION = "1.0.0"
3
+ end
data/nv.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'nv/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "nv"
8
+ spec.version = Nv::VERSION
9
+ spec.authors = ["Yasuaki Uechi"]
10
+ spec.email = ["uetchy@randompaper.co"]
11
+ spec.summary = %q{The toolbelt for nicovideo}
12
+ spec.description = %q{The commandline tool for downloading videos and mylist at nicovideo.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+
24
+ spec.add_dependency "activesupport"
25
+ spec.add_dependency "mechanize"
26
+ spec.add_dependency "thor"
27
+ spec.add_dependency "ruby-progressbar"
28
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nv
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Yasuaki Uechi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
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
+ - !ruby/object:Gem::Dependency
56
+ name: mechanize
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: thor
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: ruby-progressbar
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: The commandline tool for downloading videos and mylist at nicovideo.
98
+ email:
99
+ - uetchy@randompaper.co
100
+ executables:
101
+ - nv
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - Gemfile
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - bin/nv
111
+ - lib/nv.rb
112
+ - lib/nv/cli.rb
113
+ - lib/nv/config.rb
114
+ - lib/nv/niconico.rb
115
+ - lib/nv/niconico/base.rb
116
+ - lib/nv/niconico/fabric.rb
117
+ - lib/nv/niconico/helper.rb
118
+ - lib/nv/niconico/mylist.rb
119
+ - lib/nv/niconico/video.rb
120
+ - lib/nv/version.rb
121
+ - nv.gemspec
122
+ homepage: ''
123
+ licenses:
124
+ - MIT
125
+ metadata: {}
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 2.4.2
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: The toolbelt for nicovideo
146
+ test_files: []