ニコ生よくばり席取りちゃんスクリプト
VisualWorks(Smalltalk)でつくった。片っ端から席を取る(予約放送には勝てない)。
セッションは前に書いた記事のように作っておく。
放送を通知するhost,port,threadの組み合わせは1万回くらいhttp://live.nicovideo.jp/api/getalertinfoにアクセスして重複をのぞいた結果、以下の組み合わせが残った。alert.txtに保存しておく。
twr01.live.nicovideo.jp,2525,1000000000 twr01.live.nicovideo.jp,2526,1000000002 twr01.live.nicovideo.jp,2527,1000000004 twr01.live.nicovideo.jp,2528,1000000006 twr01.live.nicovideo.jp,2529,1000000008 twr01.live.nicovideo.jp,2530,1000000010 twr01.live.nicovideo.jp,2531,1000000012 twr01.live.nicovideo.jp,2532,1000000014 twr01.live.nicovideo.jp,2533,1000000016 twr01.live.nicovideo.jp,2534,1000000018 twr02.live.nicovideo.jp,2525,1000000001 twr02.live.nicovideo.jp,2526,1000000003 twr02.live.nicovideo.jp,2527,1000000005 twr02.live.nicovideo.jp,2528,1000000007 twr02.live.nicovideo.jp,2529,1000000009 twr02.live.nicovideo.jp,2530,1000000011 twr02.live.nicovideo.jp,2531,1000000013 twr02.live.nicovideo.jp,2532,1000000015 twr02.live.nicovideo.jp,2533,1000000017 twr02.live.nicovideo.jp,2534,1000000019
Workspaceで以下のプログラムを実行。log.txtにはプロセスの番号,放送URL,座席番号が書き込まれる。
UnixやMacOSXではtail -f log.txtとやって0番がとれたのをにやにや見る。Corei7のMac Book Proだと上に書いた20個のスレッドにアクセスしても大丈夫だったけどMac Book Airだと2個が精一杯だった。計算機の性能にあわせてalert.txtの個数変えてね。一個だけにしておくのが効率いいのかな?それにしてもこのプログラムもっとなんとかならんもんかな。
log := 'log.txt' asFilename writeStream. requestBlock := [:host :port :thread :num | [| socket stream query | socket := SocketAccessor newTCPclientToHost: host port: port. stream := socket readAppendStream. query := ''. stream nextPutAll: query; nextPut: (Character value: 0); commit. stream upTo: (Character value: 0). [stream atEnd not] whileTrue: [| dataStream lvNum reply parser parser2 contents xmlDoc request response xmlDoc2 user seetno no closedFlag requireComunityMemberFlag chatFlag unknownErrorFlag notfoundFlag cl| reply := stream upTo: (Character value: 0). parser := XML.XMLParser new. parser validate: false. xmlDoc := parser parse: reply readStream. dataStream := xmlDoc root elements first text readStream. lvNum := dataStream upTo: $,. dataStream upTo: $,. request := HttpRequest get:( 'http://watch.live.nicovideo.jp/api/getplayerstatus?v=lv' , lvNum). cl := HttpClient new. request userAgent:'vw'. response := cl executeRequest: request. response charset: 'utf-8'. parser2 := XML.XMLParser new. parser2 validate: false. contents := response contents. closedFlag := contents findString: 'closed' startingAt: 1. requireComunityMemberFlag := contents findString:'equire_community_member' startingAt: 1. chatFlag := contents findString: 'chat' startingAt: 1. unknownErrorFlag := contents findString: 'unknown' startingAt: 1. notfoundFlag := contents findString: 'notfound' startingAt:1. (((( requireComunityMemberFlag == 0 and:[chatFlag == 0]) and:[unknownErrorFlag == 0]) and:[notfoundFlag == 0]) and:[closedFlag == 0]) ifTrue:[ xmlDoc2 := parser2 parse: (contents readStream next ;yourself). user := (xmlDoc2 root elementsNamed:'user') first. seetno := (user elementsNamed:'room_seetno') first. no := seetno elements first. Processor yield. log nextPutAll: num; nextPutAll:','; nextPutAll: 'http://live.nicovideo.jp/watch/lv', lvNum; nextPutAll: ','; nextPutAll: no printString; cr.]]]]. readStream := 'alert.txt' asFilename readStream. name := 1. blocks := OrderedCollection new. [readStream atEnd] whileFalse:[ | host port thread args| host := readStream upTo:$,. port := readStream upTo:$,. thread := readStream upTo: Character cr. args := Array new:4. args at: 1 put: host. args at: 2 put: port asNumber. args at: 3 put: thread. args at: 4 put: name printString. blocks add:(requestBlock valueWithArguments: args). name := name + 1]. processes := blocks collect:[:block | block newProcess ]. processes do:[:process | process resume].
止めるときには次を実行
processes do:[:process | process terminate]. processes := nil. log close.
あー風呂はいりてー