bnicovideo 0.0.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.
- data/.gitignore +5 -0
- data/Gemfile +6 -0
- data/README +6 -0
- data/Rakefile +2 -0
- data/bnicovideo.gemspec +21 -0
- data/lib/bnicovideo/mylist.rb +63 -0
- data/lib/bnicovideo/tag.rb +24 -0
- data/lib/bnicovideo/user_session.rb +114 -0
- data/lib/bnicovideo/version.rb +3 -0
- data/lib/bnicovideo/video.rb +95 -0
- data/lib/bnicovideo.rb +9 -0
- data/nbproject/project.properties +5 -0
- data/nbproject/project.xml +13 -0
- metadata +77 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README
ADDED
data/Rakefile
ADDED
data/bnicovideo.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "bnicovideo/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "bnicovideo"
|
7
|
+
s.version = Bnicovideo::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["MH35"]
|
10
|
+
s.email = ["contact@mh35.info"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Get niconico douga video information using browser's cookie}
|
13
|
+
s.description = %q{Get niconico douga video information using browser's cookie}
|
14
|
+
|
15
|
+
s.rubyforge_project = "bnicovideo"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
# This file is mylist class file
|
4
|
+
|
5
|
+
require 'rexml/document'
|
6
|
+
require 'uri'
|
7
|
+
require 'net/http'
|
8
|
+
|
9
|
+
module Bnicovideo
|
10
|
+
# Mylist class
|
11
|
+
class Mylist
|
12
|
+
# Mylist ID
|
13
|
+
attr_reader :mylist_id
|
14
|
+
# Videos' hash. Video key is Bnicovideo::Video class object, and Content key is mylist description.
|
15
|
+
attr_reader :videos
|
16
|
+
# Mylist title
|
17
|
+
attr_reader :title
|
18
|
+
# Mylist description
|
19
|
+
attr_reader :subtitle
|
20
|
+
# Mylist author
|
21
|
+
attr_reader :author
|
22
|
+
# Init from user session and mylist ID
|
23
|
+
# user_session :: Bnicovideo::UserSession
|
24
|
+
# mylist_id :: Mylist ID
|
25
|
+
def initialize(user_session, mylist_id)
|
26
|
+
@got = false
|
27
|
+
@user_session = user_session
|
28
|
+
@mylist_id = mylist_id
|
29
|
+
end
|
30
|
+
# Force read information
|
31
|
+
def read!
|
32
|
+
@videos = []
|
33
|
+
resp = nil
|
34
|
+
Net::HTTP.start('www.nicovideo.jp') do |http|
|
35
|
+
resp = http.get('/mylist/' + @mylist_id.to_s + '?rss=atom',
|
36
|
+
{'Cookie' => 'user_session=' + @user_session.session_id})
|
37
|
+
end
|
38
|
+
resp.value
|
39
|
+
xml = REXML::Document.new(resp.body)
|
40
|
+
root = xml.root
|
41
|
+
@title = root.elements['title'].text
|
42
|
+
@subtitle = root.elements['subtitle'].text
|
43
|
+
@author = root.elements['author/name'].text
|
44
|
+
root.elements.each('entry') do |entry|
|
45
|
+
video_link = entry.elements['link'].attributes['href']
|
46
|
+
uri = URI.parse(video_link)
|
47
|
+
next unless uri.scheme == 'http' && uri.host == 'www.nicovideo.jp'
|
48
|
+
video_id = uri.path.split('/')[-1]
|
49
|
+
@videos.push({
|
50
|
+
'Video' => Bnicovideo::Video.new(@user_session, video_id),
|
51
|
+
'Content' => entry.elements['content'].text
|
52
|
+
})
|
53
|
+
end
|
54
|
+
@got = true
|
55
|
+
end
|
56
|
+
# Read information
|
57
|
+
# refresh :: If this is true, force read. Otherwise, read unless not read.
|
58
|
+
def read(refresh = false)
|
59
|
+
return if @got && !refresh
|
60
|
+
read!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
# This file has Niconico Douga tag class.
|
4
|
+
|
5
|
+
module Bnicovideo
|
6
|
+
# The tag class
|
7
|
+
class Tag
|
8
|
+
# Tag name
|
9
|
+
attr_reader :name
|
10
|
+
# True if tag is locked
|
11
|
+
attr_reader :locked
|
12
|
+
# True if tag is the category tag
|
13
|
+
attr_reader :category
|
14
|
+
# Initialize from name, locked and whether this tag is category.
|
15
|
+
# name :: Tag name
|
16
|
+
# locked :: Whether this tag is locked
|
17
|
+
# category :: Whether this tag is the category tag.
|
18
|
+
def initialize(name, locked = false, category = false)
|
19
|
+
@name = name
|
20
|
+
@locked = locked
|
21
|
+
@category = category
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
# This file has user session class.
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'sqlite3'
|
7
|
+
require 'inifile'
|
8
|
+
|
9
|
+
module Bnicovideo
|
10
|
+
# User session class
|
11
|
+
class UserSession
|
12
|
+
# User session ID
|
13
|
+
attr_reader :session_id
|
14
|
+
def initialize(sid)
|
15
|
+
@session_id = sid
|
16
|
+
end
|
17
|
+
# Get user session from Firefox(3.0 or later)
|
18
|
+
def self.init_from_firefox
|
19
|
+
ini_path = File.join(ENV['APPDATA'], 'Mozilla', 'Firefox', 'profiles.ini')
|
20
|
+
ini_hash = IniFile.load(ini_path).to_h
|
21
|
+
profile_path = nil
|
22
|
+
ini_hash.each do |k, v|
|
23
|
+
next unless v['Name'] == 'default'
|
24
|
+
relative = (v['IsRelative'] != '0')
|
25
|
+
input_path = v['Path']
|
26
|
+
if relative
|
27
|
+
profile_path = File.join(ENV['APPDATA'], 'Mozilla', 'Firefox', input_path)
|
28
|
+
else
|
29
|
+
profile_path = input_path
|
30
|
+
end
|
31
|
+
sql_path = File.join(profile_path, 'cookies.sqlite')
|
32
|
+
conn = SQLite3::Database.new(sql_path)
|
33
|
+
val = conn.get_first_value("select value from moz_cookies" +
|
34
|
+
" where host='.nicovideo.jp' AND name='user_session'")
|
35
|
+
return self.new(val)
|
36
|
+
end
|
37
|
+
return nil
|
38
|
+
end
|
39
|
+
# Get user session from Google Chrome
|
40
|
+
def self.init_from_chrome
|
41
|
+
sql_path = File.join(ENV['LOCALAPPDATA'], 'Google','Chrome', 'User Data', 'Default', 'Cookies')
|
42
|
+
conn = SQLite3::Database.new(sql_path)
|
43
|
+
val = conn.get_first_value("select value from cookies" +
|
44
|
+
" where host_key='.nicovideo.jp' AND name='user_session'")
|
45
|
+
conn.close
|
46
|
+
return self.new(val)
|
47
|
+
end
|
48
|
+
# Get user session from Internet Explorer
|
49
|
+
def self.init_from_ie
|
50
|
+
cookies_path = File.join(ENV['APPDATA'], 'Microsoft', 'Windows', 'Cookies', 'Low')
|
51
|
+
Dir.open(cookies_path) do |dir|
|
52
|
+
dir.each do |fn|
|
53
|
+
next unless (/.*@nicovideo.*/ =~ fn)
|
54
|
+
File.open(fn) do |f|
|
55
|
+
cb = f.read
|
56
|
+
cs = cb.split(/\*\n/)
|
57
|
+
cs.each do |c|
|
58
|
+
ca = c.split(/\n/)
|
59
|
+
return self.new(ca[1]) if ca[0] == 'user_session'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
return nil
|
65
|
+
end
|
66
|
+
# Get user session from Safari
|
67
|
+
def self.init_from_safari
|
68
|
+
cookie_path = File.join(ENV['APPDATA'], 'Apple Computer', 'Safari',
|
69
|
+
'Cookies', 'Cookies.binarycookies')
|
70
|
+
bin = nil
|
71
|
+
File.open(cookie_path, 'rb') do |file|
|
72
|
+
bin = file.read
|
73
|
+
end
|
74
|
+
raise 'Invalid Cookie file' unless bin[0..3] == 'cook'
|
75
|
+
page_num = bin[4..7].unpack('N')[0]
|
76
|
+
pages_length = []
|
77
|
+
page_num.times do |i|
|
78
|
+
page_length = bin[(8 + i * 4)..(11 + i * 4)].unpack('N')[0]
|
79
|
+
pages_length.push(page_length)
|
80
|
+
end
|
81
|
+
read_ptr = 8 + page_num * 4
|
82
|
+
pages_length.each do |pgl|
|
83
|
+
page = bin[read_ptr..(read_ptr + pgl - 1)]
|
84
|
+
cookies_num = page[4..7].unpack('V')[0]
|
85
|
+
nread_ptr = read_ptr
|
86
|
+
cookies_offset = []
|
87
|
+
cookies_num.length.times do |i|
|
88
|
+
cookie_offset = page[(8 + i * 4)..(11 + i * 4)].unpack('V')[0]
|
89
|
+
cookies_offset.push(cookie_offset)
|
90
|
+
end
|
91
|
+
nread_ptr += 12 + cookies_num * 4
|
92
|
+
read_ptr += pgl
|
93
|
+
cookies_offset.each do |cof|
|
94
|
+
cookie_length = page[cof..(cof + 3)].unpack('V')[0]
|
95
|
+
cookie_bin = page[cof..(cof + cookie_length - 1)]
|
96
|
+
offset_url = page[(cof + 16)..(cof + 19)].unpack('V')[0]
|
97
|
+
offset_name = page[(cof + 20)..(cof + 23)].unpack('V')[0]
|
98
|
+
offset_path = page[(cof + 24)..(cof + 27)].unpack('V')[0]
|
99
|
+
offset_value = page[(cof + 28)..(cof + 31)].unpack('V')[0]
|
100
|
+
url_end = (/\x00/ =~ cookie_bin[offset_url..-1])
|
101
|
+
url = cookie_bin[offset_url, url_end]
|
102
|
+
name_end = (/\x00/ =~ cookie_bin[offset_name..-1])
|
103
|
+
name = cookie_bin[offset_name, name_end]
|
104
|
+
path_end = (/\x00/ =~ cookie_bin[offset_path..-1])
|
105
|
+
path = cookie_bin[offset_path, path_end]
|
106
|
+
value_end = (/\x00/ =~ cookie_bin[offset_value..-1])
|
107
|
+
value = cookie_bin[offset_value, value_end]
|
108
|
+
return self.new(value) if (/nicovideo\.jp$/ =~ url) && (name == 'user_session')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
return nil
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
# This file has video class.
|
4
|
+
|
5
|
+
require 'net/http'
|
6
|
+
require 'rexml/document'
|
7
|
+
require 'date'
|
8
|
+
|
9
|
+
module Bnicovideo
|
10
|
+
# This class represents video of Niconico Douga
|
11
|
+
class Video
|
12
|
+
# Video ID
|
13
|
+
attr_reader :video_id
|
14
|
+
# Video title
|
15
|
+
attr_reader :title
|
16
|
+
# Video description
|
17
|
+
attr_reader :description
|
18
|
+
# Thumbnail URL
|
19
|
+
attr_reader :thumbnail_url
|
20
|
+
# DateTime object when the video was post
|
21
|
+
attr_reader :first_retrieve
|
22
|
+
# Video length in seconds
|
23
|
+
attr_reader :length
|
24
|
+
# Movie type(mp4, flv, ...)
|
25
|
+
attr_reader :movie_type
|
26
|
+
# How many times this video was viewed
|
27
|
+
attr_reader :view_counter
|
28
|
+
# How many comments were post
|
29
|
+
attr_reader :comment_num
|
30
|
+
# How many mylists have this video
|
31
|
+
attr_reader :mylist_counter
|
32
|
+
# Embeddable this video
|
33
|
+
attr_reader :embeddable
|
34
|
+
# Whether this video can play in Niconico live streaming
|
35
|
+
attr_reader :live_allowed
|
36
|
+
# Tags' hash. Key is language and value is the array of Bnicovideo::Tag object.
|
37
|
+
attr_reader :tags
|
38
|
+
# User id of this video's author
|
39
|
+
attr_reader :user_id
|
40
|
+
# Whether this video was deleted
|
41
|
+
attr_reader :deleted
|
42
|
+
# Initialize from user session and video ID
|
43
|
+
# user_session :: Bnicovideo::UserSession object
|
44
|
+
# video_id :: Video ID
|
45
|
+
def initialize(user_session, video_id)
|
46
|
+
@user_session = user_session
|
47
|
+
@video_id = video_id
|
48
|
+
@info_got = false
|
49
|
+
end
|
50
|
+
# Get video information
|
51
|
+
# refresh :: If this is set true, force get. Otherwise, get only if not gotten.
|
52
|
+
def get_info(refresh = false)
|
53
|
+
if @info_got && !refresh
|
54
|
+
return
|
55
|
+
end
|
56
|
+
resp = nil
|
57
|
+
Net::HTTP.start('ext.nicovideo.jp') do |http|
|
58
|
+
resp = http.get('/api/getthumbinfo/' + @video_id,
|
59
|
+
{'Cookie' => 'user_session=' + @user_session.session_id})
|
60
|
+
end
|
61
|
+
resp.value
|
62
|
+
xml = REXML::Document.new(resp.body)
|
63
|
+
root = xml.root
|
64
|
+
if root.attributes['status'] == 'ok'
|
65
|
+
@title = root.elements['thumb/title'].text
|
66
|
+
@description = root.elements['thumb/description'].text
|
67
|
+
@thumbnail_url = root.elements['thumb/thumbnail_url'].text
|
68
|
+
@first_retrieve = DateTime.parse(root.elements['thumb/first_retrieve'].text)
|
69
|
+
length_string = root.elements['thumb/length'].text
|
70
|
+
length_arr = length_string.split(':')
|
71
|
+
@length = length_arr[0].to_i * 60 + length_arr[1].to_i
|
72
|
+
@movie_type = root.elements['thumb/movie_type'].text
|
73
|
+
@view_counter = root.elements['thumb/view_counter'].text.to_i
|
74
|
+
@comment_num = root.elements['thumb/comment_num'].text.to_i
|
75
|
+
@mylist_counter = root.elements['thumb/mylist_counter'].text.to_i
|
76
|
+
@embeddable = root.elements['thumb/embeddable'].text == '1'
|
77
|
+
@live_allowed = root.elements['thumb/no_live_play'].text == '0'
|
78
|
+
@tags = {}
|
79
|
+
root.elements.each('thumb/tags') do |tse|
|
80
|
+
key = tse.attributes['domain']
|
81
|
+
dtags = []
|
82
|
+
tse.elements.each('tag') do |tge|
|
83
|
+
dtags.push(Bnicovideo::Tag.new(tge.text,
|
84
|
+
tge.attributes['lock'] == '1', tge.attributes['category'] == '1'))
|
85
|
+
end
|
86
|
+
@tags[key] = dtags
|
87
|
+
end
|
88
|
+
@user_id = root.elements['thumb/user_id'].text
|
89
|
+
else
|
90
|
+
@deleted = true
|
91
|
+
end
|
92
|
+
@info_got = true
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/bnicovideo.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# This file has the top level of module
|
2
|
+
|
3
|
+
# Top level module of bnicovideo gem.
|
4
|
+
module Bnicovideo
|
5
|
+
autoload :Mylist, File.join(File.dirname(__FILE__), 'bnicovideo', 'mylist.rb')
|
6
|
+
autoload :Tag, File.join(File.dirname(__FILE__), 'bnicovideo', 'tag.rb')
|
7
|
+
autoload :UserSession, File.join(File.dirname(__FILE__), 'bnicovideo', 'user_session.rb')
|
8
|
+
autoload :Video, File.join(File.dirname(__FILE__), 'bnicovideo', 'video.rb')
|
9
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<project xmlns="http://www.netbeans.org/ns/project/1">
|
3
|
+
<type>org.netbeans.modules.ruby.rubyproject</type>
|
4
|
+
<configuration>
|
5
|
+
<data xmlns="http://www.netbeans.org/ns/ruby-project/1">
|
6
|
+
<name>bnicovideo</name>
|
7
|
+
<source-roots>
|
8
|
+
<root id="src.dir"/>
|
9
|
+
</source-roots>
|
10
|
+
<test-roots/>
|
11
|
+
</data>
|
12
|
+
</configuration>
|
13
|
+
</project>
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bnicovideo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- MH35
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2012-02-24 00:00:00 +09:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Get niconico douga video information using browser's cookie
|
22
|
+
email:
|
23
|
+
- contact@mh35.info
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- .gitignore
|
32
|
+
- Gemfile
|
33
|
+
- README
|
34
|
+
- Rakefile
|
35
|
+
- bnicovideo.gemspec
|
36
|
+
- lib/bnicovideo.rb
|
37
|
+
- lib/bnicovideo/mylist.rb
|
38
|
+
- lib/bnicovideo/tag.rb
|
39
|
+
- lib/bnicovideo/user_session.rb
|
40
|
+
- lib/bnicovideo/version.rb
|
41
|
+
- lib/bnicovideo/video.rb
|
42
|
+
- nbproject/project.properties
|
43
|
+
- nbproject/project.xml
|
44
|
+
has_rdoc: true
|
45
|
+
homepage: ""
|
46
|
+
licenses: []
|
47
|
+
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
segments:
|
67
|
+
- 0
|
68
|
+
version: "0"
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project: bnicovideo
|
72
|
+
rubygems_version: 1.3.7
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: Get niconico douga video information using browser's cookie
|
76
|
+
test_files: []
|
77
|
+
|