Skip to content

Commit 07d8b91

Browse files
committed
add message post for niconama.py
1 parent 7be2348 commit 07d8b91

File tree

1 file changed

+87
-2
lines changed

1 file changed

+87
-2
lines changed

python/niconama.py

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
import struct
1111
import cookielib
1212
import argparse
13+
import time
1314
from HTMLParser import HTMLParser
1415

16+
1517
class NicoLive:
1618

1719
LOGIN_URL = 'https://secure.nicovideo.jp/secure/login'
@@ -22,11 +24,16 @@ class NicoLive:
2224
THREAD_TEMPLATE = '<thread thread="%s" version="20061206" res_from="-1"/>'
2325
MY_URL = 'http://live.nicovideo.jp/my'
2426

27+
GETPOSTKEY_URL = 'http://watch.live.nicovideo.jp/api/getpostkey?thread=%s&block_no=%s'
28+
CHAT_THREAD_TEMPLATE = '<chat thread="%s" ticket="%s" vpos="%s" postkey="%s" mail="184" user_id="%s" premium="%s">%s</chat>'
29+
2530
def __init__(self):
2631
self.login_status = False
2732
self.thread = None
2833
self.addr = None
2934
self.port = None
35+
self.user_id = None
36+
self.premium = None
3037

3138
def login(self, params):
3239
cookie = cookielib.CookieJar()
@@ -36,7 +43,7 @@ def login(self, params):
3643
if cookie._cookies['.nicovideo.jp']:
3744
self.login_status = True
3845

39-
def watch(self, lv, cb):
46+
def _get_play_status_dom(self, lv):
4047
if self.login_status is False:
4148
print 'you haven\'t login'
4249
exit(0)
@@ -46,6 +53,10 @@ def watch(self, lv, cb):
4653
if status['status'] == 'fail':
4754
print 'program was finished or login failed'
4855
exit(0)
56+
return dom
57+
58+
def watch(self, lv, cb):
59+
dom = self._get_play_status_dom(lv)
4960

5061
for item in dom.findall('.//'):
5162
if item.tag == 'thread':
@@ -66,7 +77,8 @@ def _get_msg(self, cb):
6677
sock.send(struct.pack('b',0))
6778
try:
6879
data = sock.recv(1024)
69-
cb(data)
80+
if cb(data) is False:
81+
return data
7082
except(KeyboardInterrupt, IOError), e:
7183
print e
7284
exit(0)
@@ -127,6 +139,76 @@ def my(self):
127139
for lv in favorite_lv_set:
128140
print '%s : %s' % (lv[0], lv[1])
129141

142+
def _get_latest_msg_dom(self):
143+
data = self._get_msg(lambda x: False)
144+
thread_token_last_pos = data.index('/>')
145+
return etree.fromstring(data[:thread_token_last_pos+2])
146+
147+
def _get_postkey(self, block_no):
148+
postkey_url = self.GETPOSTKEY_URL % (self.thread, block_no)
149+
postkey = self._urlopen(postkey_url, None, lambda x: x)
150+
return postkey.split('=')[1]
151+
152+
def _post_comment(self, ticket, vpos, postkey, comment):
153+
message = self.CHAT_THREAD_TEMPLATE % (self.thread, ticket, vpos, postkey, self.user_id, self.premium, comment)
154+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
155+
sock.connect((self.addr, int(self.port)))
156+
sock.send(message)
157+
sock.send(struct.pack('b',0))
158+
try:
159+
data = sock.recv(1024)
160+
chat_last_pos = data.index('/>')
161+
return etree.fromstring(data[:chat_last_pos+2])
162+
except Exception, e:
163+
print 'unhandled exception', e
164+
exit(0)
165+
166+
def post(self, lv, comment):
167+
print lv, comment
168+
dom = self._get_play_status_dom(lv)
169+
170+
for item in dom.findall('.//'):
171+
if item.tag == 'thread':
172+
self.thread = item.text
173+
elif item.tag == 'addr':
174+
self.addr = item.text
175+
elif item.tag == 'port':
176+
self.port = item.text
177+
elif item.tag == 'user_id':
178+
self.user_id = item.text
179+
elif item.tag == 'start_time':
180+
start_time = item.text
181+
elif item.tag == 'is_premium':
182+
self.premium = item.text
183+
184+
# get latest comment
185+
dom = self._get_latest_msg_dom()
186+
if dom.tag != 'thread':
187+
print 'program was finished or login failed'
188+
exit(0)
189+
190+
ticket = dom.attrib['ticket']
191+
last_res = dom.attrib['last_res']
192+
193+
# get block_no
194+
block_no = int(last_res) / 100
195+
196+
# calc vpos
197+
vpos = (int(time.time()) - int(start_time)) * 100
198+
199+
# get postkey
200+
postkey = self._get_postkey(block_no)
201+
202+
# send message
203+
dom = self._post_comment(ticket, vpos, postkey, comment)
204+
print dom.attrib
205+
if dom.attrib['status'] == '0':
206+
print 'message post success'
207+
else:
208+
print 'message post fail'
209+
210+
211+
130212
class MyHTMLParser(HTMLParser):
131213

132214
WATCH_RE = re.compile('http://live.nicovideo.jp/watch/(lv[0-9]+)', re.I)
@@ -147,6 +229,7 @@ def _print_msg(msg):
147229
print msg
148230
parser = argparse.ArgumentParser(description='NicoLive Comment View')
149231
parser.add_argument('-lv', type=str, help='target nicolive lv')
232+
parser.add_argument('-post', type=str, help='post message')
150233
parser.add_argument('-my', action='store_true', help='show favorite community\'s live')
151234
args = parser.parse_args()
152235

@@ -157,6 +240,8 @@ def _print_msg(msg):
157240
if args.my:
158241
#nicolive.antena(params)
159242
nicolive.my()
243+
elif args.lv and args.post:
244+
nicolive.post(args.lv, args.post)
160245
elif args.lv:
161246
nicolive.watch(args.lv, _print_msg)
162247
else:

0 commit comments

Comments
 (0)