nicolive 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 96d7b04dccf8e001951dbebb438c5c544c3ab8e8
4
+ data.tar.gz: 40299ef002d758f803f13ef38e711cb6bf37618a
5
+ SHA512:
6
+ metadata.gz: a9379df5e95ebe189f938f7110276f0eecd13621d652037755f157f08cd0f52563b033cb39134b1ca933ca33b29ca2db045ab04f5ffafd75785db0a171cf9411
7
+ data.tar.gz: a30f899571234f29a5a274b799a08945b521c28b39b7d85ce8718b70ee69ad65e18f65dd851bfaa6cca6cfe47a2712e7fbdfabe7e11c67b6b14be85f9a2fe19a
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.direnv
11
+ /.envrc
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
4
+ script:
5
+ - rake test
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nicolive.gemspec
4
+ gemspec
@@ -0,0 +1,44 @@
1
+ # Nicolive
2
+
3
+ An Accessor for a Nicovideo live.
4
+ This make easy to fetch comments.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'nicolive'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ ```bash
17
+ $ bundle
18
+ ```
19
+
20
+ Or install it yourself as:
21
+
22
+ ```bash
23
+ $ gem install nicolive
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ Write credential
29
+
30
+ ```ruby
31
+ client = Nicolive.login('your_mail', 'your_password')
32
+ channel = 'lv236367556' #Nicovideo live id
33
+ client.watch(channel) do |chat|
34
+ puts "#{chat.date} #{chat.comment}"
35
+ end
36
+ ```
37
+
38
+ ## Contributing
39
+
40
+ 1. Fork it ( https://github.com/maruware/nicolive/fork )
41
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
42
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
43
+ 4. Push to the branch (`git push origin my-new-feature`)
44
+ 5. Create a new Pull Request
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ require 'rake/testtask'
6
+ Rake::TestTask.new(:test) do |test|
7
+
8
+ test.test_files = FileList["test/*.rb"].exclude("test/test_helper.rb")
9
+ test.verbose = false
10
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "nicolive"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,16 @@
1
+ require "nicolive/version"
2
+ require "nicolive/client"
3
+ require "nicolive/thread"
4
+ require "nicolive/chat"
5
+ require "nicolive/user"
6
+
7
+ module Nicolive
8
+ ENDPOINT_GETPLAYERSTATUS = 'http://watch.live.nicovideo.jp/api/getplayerstatus'
9
+ ENDPOINT_LOGIN_FORM = 'https://secure.nicovideo.jp/secure/login_form'
10
+ ENDPOINT_TOP = 'http://live.nicovideo.jp'
11
+ ENDPOINT_USER_INFO = 'http://api.ce.nicovideo.jp/api/v1/user.info'
12
+ def login(mail, password)
13
+ Client.new(mail, password)
14
+ end
15
+ module_function :login
16
+ end
@@ -0,0 +1,44 @@
1
+ module Nicolive
2
+ class Chat
3
+ attr_reader :comment, :mail, :vpos, :date, :user_id, :premium, :anonymity, :locale, :score, :origin, :user
4
+ def initialize(comment, mail, vpos, date, user_id, premium, anonymity, locale, score, origin)
5
+ @comment = comment
6
+ @mail = mail
7
+ @vpos = vpos
8
+ @date = date
9
+ @user_id = user_id
10
+ @premium = premium
11
+ @anonymity = anonymity
12
+ @locale = locale
13
+ @score = score
14
+ @origin = origin
15
+
16
+ @user = unless anonymity
17
+ User.fetch(user_id)
18
+ end
19
+ end
20
+ def self.parse(node)
21
+ comment = node.text
22
+ vpos = node.attribute('vpos').value
23
+ mail = node.attribute('mail').value if node.attribute('mail')
24
+ date_ts = node.attribute('date').value.to_i
25
+ date = Time.at(date_ts)
26
+ user_id = node.attribute('user_id').value
27
+ premium = node.attribute('premium').value if node.attribute('premium')
28
+ anonymity = node.attribute('anonymity').value.to_i if node.attribute('anonymity')
29
+ score = node.attribute('score').value if node.attribute('score')
30
+ locale = node.attribute('locale').value if node.attribute('locale')
31
+ origin = node.attribute('origin').value if node.attribute('origin')
32
+
33
+ Chat.new(comment, vpos, mail, date, user_id, premium, anonymity, locale, score, origin)
34
+ end
35
+
36
+ def hb_comment?
37
+ return /^\/hb/ === comment
38
+ end
39
+
40
+ def anonymity?
41
+ return @anonymity==1 ? true : false
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,137 @@
1
+ require 'mechanize'
2
+ require 'socket'
3
+ require 'nokogiri'
4
+ require 'eventmachine'
5
+ require 'addressable/uri'
6
+
7
+ module Nicolive
8
+ class Client
9
+ def initialize(mail, password)
10
+
11
+ @agent = Mechanize.new
12
+ @agent.user_agent_alias = 'Mac Safari'
13
+
14
+ @agent.get Addressable::URI.parse(ENDPOINT_LOGIN_FORM) do |page|
15
+ res = page.form_with id: 'login_form' do |form|
16
+ form.field_with(name: 'mail_tel').value = mail
17
+ form.field_with(name: 'password').value = password
18
+ end.click_button
19
+ end
20
+
21
+ @events = {}
22
+ end
23
+
24
+ def watch(channel, &block)
25
+ t = fetch_thread(channel)
26
+
27
+ if EventMachine.reactor_running?
28
+ connect t, &block
29
+ else
30
+ if EventMachine.epoll?
31
+ EventMachine.epoll
32
+ elsif EventMachine.kqueue?
33
+ EventMachine.kqueue
34
+ else
35
+ Kernel.warn('Your OS does not support epoll or kqueue.')
36
+ end
37
+
38
+ EventMachine.run do
39
+ connect t, &block
40
+ end
41
+ end
42
+
43
+ self
44
+ end
45
+
46
+ def on_disconnected(&block)
47
+ on(:disconnected, &block)
48
+ end
49
+
50
+ def stop()
51
+ EventMachine.stop_event_loop
52
+ end
53
+
54
+ def onair_channel_top3
55
+ page = @agent.get Addressable::URI.parse(ENDPOINT_TOP)
56
+ channnels = page.search('.item.onair a.item_link').map do |link|
57
+ url = link.attribute('href').value
58
+ r = url.match(/(?<channel>lv[0-9]+)/)
59
+ r['channel']
60
+ end
61
+ channnels
62
+ end
63
+
64
+ private
65
+ def fetch_thread(channel)
66
+ uri = Addressable::URI.parse(ENDPOINT_GETPLAYERSTATUS)
67
+ uri.query_values = {v: channel}
68
+ page = @agent.get uri.to_s
69
+ if page.search('error').any?
70
+ code = page.search('error').first.search('code').text
71
+ throw RuntimeError.new("error [#{code}]")
72
+ end
73
+ thread = page.search('thread').text
74
+ addr = page.search('addr').text
75
+ port = page.search('port').text
76
+
77
+ Thread.new(thread, addr, port)
78
+ end
79
+
80
+ def connect(thread, &block)
81
+ thread_req = "<thread thread=\"#{thread.thread}\" version=\"20061206\" res_from=\"-1\"/>\0"
82
+ con = EventMachine::connect thread.addr, thread.port, Connection
83
+ con.client = self
84
+ on_disconnected do
85
+ stop()
86
+ end
87
+ con.start thread_req, &block
88
+ end
89
+
90
+ def on(event, &block)
91
+ if block_given?
92
+ unless @events.has_key?(event)
93
+ @events[event] = []
94
+ end
95
+ @events[event] << block
96
+ self
97
+ else
98
+ @events[event]
99
+ end
100
+ end
101
+
102
+ def invoke_callback(event, *args)
103
+ if @events.has_key?(event)
104
+ callbacks = @events[event]
105
+ callbacks.each do |callback|
106
+ callback.call(*args)
107
+ end
108
+ end
109
+ end
110
+
111
+ class Connection < EventMachine::Connection
112
+ attr_accessor :client
113
+ def start(req, &block)
114
+ @block = block
115
+ send_data req
116
+ end
117
+
118
+ def receive_data(data)
119
+ doc = Nokogiri::HTML.parse(data)
120
+ chat_nodes = doc.xpath('//chat')
121
+ unless chat_nodes.any?
122
+ return
123
+ end
124
+
125
+ chat_node = chat_nodes.first
126
+ chat = Chat.parse(chat_node)
127
+
128
+ if chat.comment == '/disconnect'
129
+ client.send(:invoke_callback, :disconnected)
130
+ return
131
+ end
132
+ @block.call(chat)
133
+ end
134
+ end
135
+ end
136
+
137
+ end
@@ -0,0 +1,11 @@
1
+ module Nicolive
2
+ class Thread
3
+ attr_reader :thread, :addr, :port
4
+
5
+ def initialize(thread, addr, port)
6
+ @thread = thread
7
+ @addr = addr
8
+ @port = port
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,27 @@
1
+ require 'mechanize'
2
+ require 'addressable/uri'
3
+
4
+ module Nicolive
5
+ class User
6
+ attr_reader :id, :nickname, :thumbnail_url
7
+ def initialize(id, nickname, thumbnail_url)
8
+ @id = id
9
+ @nickname = nickname
10
+ @thumbnail_url = thumbnail_url
11
+ end
12
+ def self.fetch(user_id)
13
+ id = user_id.to_i
14
+ uri = Addressable::URI(ENDPOINT_USER_INFO)
15
+ uri.query_values = {user_id: user_id}
16
+ page = Mechanize.new.get uri.to_s
17
+
18
+ user_node = page.search('user').first
19
+ nickname = user_node.xpath('nickname').first.text
20
+ id = user_node.xpath('id').first.text
21
+ thumbnail_url = user_node.xpath('thumbnail_url').first.text
22
+
23
+ User.new(id, nickname, thumbnail_url)
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module Nicolive
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'nicolive/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "nicolive"
8
+ spec.version = Nicolive::VERSION
9
+ spec.authors = ["maruware"]
10
+ spec.email = ["me@maruware.com"]
11
+
12
+ spec.summary = %q{Accessor for a Nicovideo live.}
13
+ spec.description = %q{Accessor for a Nicovideo live.}
14
+ spec.homepage = "https://github.com/maruware/nicolive"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.test_files = spec.files.grep(%r{^(test)/})
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency 'mechanize', '~> 2.7'
23
+ spec.add_dependency 'eventmachine', '>= 1.0.3'
24
+ spec.add_dependency 'addressable', '>= 2.3.8'
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.8"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency 'minitest', '~> 5.0.0'
29
+ end
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nicolive
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - maruware
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-11-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mechanize
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: eventmachine
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.3
41
+ - !ruby/object:Gem::Dependency
42
+ name: addressable
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 2.3.8
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 2.3.8
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.8'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 5.0.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 5.0.0
97
+ description: Accessor for a Nicovideo live.
98
+ email:
99
+ - me@maruware.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".travis.yml"
106
+ - Gemfile
107
+ - README.md
108
+ - Rakefile
109
+ - bin/console
110
+ - bin/setup
111
+ - lib/nicolive.rb
112
+ - lib/nicolive/chat.rb
113
+ - lib/nicolive/client.rb
114
+ - lib/nicolive/thread.rb
115
+ - lib/nicolive/user.rb
116
+ - lib/nicolive/version.rb
117
+ - nicolive.gemspec
118
+ homepage: https://github.com/maruware/nicolive
119
+ licenses: []
120
+ metadata: {}
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 2.4.5.1
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: Accessor for a Nicovideo live.
141
+ test_files: []