10
10
import struct
11
11
import cookielib
12
12
import argparse
13
+ import time
13
14
from HTMLParser import HTMLParser
14
15
16
+
15
17
class NicoLive :
16
18
17
19
LOGIN_URL = 'https://secure.nicovideo.jp/secure/login'
@@ -22,11 +24,16 @@ class NicoLive:
22
24
THREAD_TEMPLATE = '<thread thread="%s" version="20061206" res_from="-1"/>'
23
25
MY_URL = 'http://live.nicovideo.jp/my'
24
26
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
+
25
30
def __init__ (self ):
26
31
self .login_status = False
27
32
self .thread = None
28
33
self .addr = None
29
34
self .port = None
35
+ self .user_id = None
36
+ self .premium = None
30
37
31
38
def login (self , params ):
32
39
cookie = cookielib .CookieJar ()
@@ -36,7 +43,7 @@ def login(self, params):
36
43
if cookie ._cookies ['.nicovideo.jp' ]:
37
44
self .login_status = True
38
45
39
- def watch (self , lv , cb ):
46
+ def _get_play_status_dom (self , lv ):
40
47
if self .login_status is False :
41
48
print 'you haven\' t login'
42
49
exit (0 )
@@ -46,6 +53,10 @@ def watch(self, lv, cb):
46
53
if status ['status' ] == 'fail' :
47
54
print 'program was finished or login failed'
48
55
exit (0 )
56
+ return dom
57
+
58
+ def watch (self , lv , cb ):
59
+ dom = self ._get_play_status_dom (lv )
49
60
50
61
for item in dom .findall ('.//' ):
51
62
if item .tag == 'thread' :
@@ -66,7 +77,8 @@ def _get_msg(self, cb):
66
77
sock .send (struct .pack ('b' ,0 ))
67
78
try :
68
79
data = sock .recv (1024 )
69
- cb (data )
80
+ if cb (data ) is False :
81
+ return data
70
82
except (KeyboardInterrupt , IOError ), e :
71
83
print e
72
84
exit (0 )
@@ -127,6 +139,76 @@ def my(self):
127
139
for lv in favorite_lv_set :
128
140
print '%s : %s' % (lv [0 ], lv [1 ])
129
141
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
+
130
212
class MyHTMLParser (HTMLParser ):
131
213
132
214
WATCH_RE = re .compile ('http://live.nicovideo.jp/watch/(lv[0-9]+)' , re .I )
@@ -147,6 +229,7 @@ def _print_msg(msg):
147
229
print msg
148
230
parser = argparse .ArgumentParser (description = 'NicoLive Comment View' )
149
231
parser .add_argument ('-lv' , type = str , help = 'target nicolive lv' )
232
+ parser .add_argument ('-post' , type = str , help = 'post message' )
150
233
parser .add_argument ('-my' , action = 'store_true' , help = 'show favorite community\' s live' )
151
234
args = parser .parse_args ()
152
235
@@ -157,6 +240,8 @@ def _print_msg(msg):
157
240
if args .my :
158
241
#nicolive.antena(params)
159
242
nicolive .my ()
243
+ elif args .lv and args .post :
244
+ nicolive .post (args .lv , args .post )
160
245
elif args .lv :
161
246
nicolive .watch (args .lv , _print_msg )
162
247
else :
0 commit comments