Skip to content

Instantly share code, notes, and snippets.

@GNQG
Created September 8, 2016 11:44
Show Gist options
  • Save GNQG/0f10bb68aabed84057726c4c33c1553d to your computer and use it in GitHub Desktop.
Save GNQG/0f10bb68aabed84057726c4c33c1553d to your computer and use it in GitHub Desktop.
from urllib import urlencode
from urllib2 import urlopen,HTTPError,URLError
import socket
import re
import json
try:
from unescape_charref import unescape_charref
except ImportError:
unescape_charref=None
class DEE2JSONDecoder(json.JSONDecoder):
def __init__(self,encoding=None,**kwgs):
# some control sequences are not escaped in string
# ex. eventid=105(headline) line 319 u'\t\t\t"Info" : "...\t(^^)"'
# toavoid this set strict=False
json.JSONDecoder.__init__(self,encoding,strict=False,**kwgs)
class DEE2EventData(object):
DEE2_URL='http://manbow.nothing.sh/event/event.cgi'
GETJSON_PARAM=(('action','JSONList'),)
def __init__(self,eventid,name=None):
self._eventid=int(eventid)
self._name=name if isinstance(name,basestring) else None
self._songlist=[]
self._headline=[]
def getsonglist(self,utf8=False):
tmpjson=self._getjson(utf8)
if self._name is None:
self._name=tmpjson.get('EventName')
self._songlist=tmpjson['Data']
def getheadline(self,utf8=False):
tmpjson=self._getjson(utf8,(('output','headline'),))
if self._name is None:
self._name=tmpjson.get('EventName')
self._headline=tmpjson['Data']
def get(self,utf8=False):
self.getsonglist(utf8)
self.getheadline(utf8)
def _getjson(self,utf8,iterable=None):
param=self.GETJSON_PARAM
if utf8==True:
param+=(('utf-8','on'),)
if iterable:
param+=iterable
query=urlencode(param+(('event',self._eventid),))
try:
ret=urlopen(self.DEE2_URL+'?'+query).read()
except URLError,e:
if isinstance(e.reason, socket.timeout):
raise Exception("timeout: %s" % e)
else:
raise
except socket.timeout,e:
raise Exception("timeout: %s" % e)
# fix structure error: [{...},{...},...,{...},] -> [{...},{...},...,{...}]
# this may be happen when last registered entry is deleted
# ex. eventid=104 BOFU2015
ret=re.sub(
r'}\s*,\s*\]\s*}\s*\Z',
r'}]}',
ret
)
if not utf8:
# remove extra escapes for Damemoji: [cp932 1st byte]\\ -> [cp932 1st byte]\
ret=re.sub(
'([\x81-\x9f\xe0-\xfc]'+r'\\)\\',
r'\1',
ret
)
# for output=headline
# truncated multibyte character involves '"' when decoded
# to avoid this, first, inserting ' ' before '"'
ret=re.sub(
r'^(\s*\".*?\"\s*:\s*\".*)\"(\s*[,\]}]?\s*)$',
r'\1 "\2',
ret,flags=re.MULTILINE
)
# second, decode this with errors='replace'
# truncated character('[\x81-\x9f\xe0-\xfc] ') generates '\ufffd'
# valid string does not change ' '
ret=ret.decode('cp932',errors='replace')
# and last, remove ' ' or '\ufffd' from end of each string
ret=re.sub(
ur'^(\s*\".*?\"\s*:\s*\".*)[ \ufffd]\"(\s*[,\]}]?\s*)$',
ur'\1"\2',
ret,flags=re.MULTILINE
)
else:
# if utf8 mode, only to do is decoding string
ret=ret.decode('cp932',errors='replace')
if unescape_charref:
# unescape character reference
ret=unescape_charref(ret)
# in some cases strings contain unescaped '"'
# ex. eventid=26 line 2 '\t"EventName" : "B-1 "Unrestricted"" ,'
# add escapes to those
ret=re.sub(
ur'(^\s*\".*?\"\s*:\s*\")(.*\".*)(?=\"\s*[,\]}]?\s*$)',
lambda s:s.group(1)+re.sub(
ur'((^|[^\\])(?:\\\\)*)(?=\")',
ur'\1'+ur'\\',
s.group(2)
),
ret,flags=re.MULTILINE
)
return json.loads(ret,cls=DEE2JSONDecoder)
def clear(self):
self._eventid=None
self._name=None
self._songlist=[]
self._headline=[]
@property
def eventid(self):
return self._eventid
@eventid.setter
def eventid(self,evid):
if not getattr(evid,'__int__') or int(evid)<=0:
raise ValueError('eventid must be positive integer')
elif int(evid)==self.eventid:
self._eventid=int(evid)
else:
self.clear()
self._eventid=int(evid)
@eventid.deleter
def eventid(self):
self.clear()
@property
def eventname(self):
return self._name
@eventname.setter
def eventname(self,name):
self._name=name
@eventname.deleter
def eventname(self):
self._name=None
@property
def songlist(self):
return self._songlist
@songlist.setter
def songlist(self,sl):
if getattr(sl, '__iter__'):
self._songlist=list(sl)
else:
self._songlist=[]
@songlist.deleter
def songlist(self):
self._songlist=[]
@property
def headline(self):
return self._headline
@headline.setter
def headline(self,hl):
if getattr(hl, '__iter__'):
self._headline=list(hl)
else:
self._headline=[]
@headline.deleter
def headline(self):
self._headline=[]
if __name__=='__main__':
import sys
import time
args=sys.argv
if len(args)>=2:
for evid in args[1:]:
try:
ev=DEE2EventData(evid)
except:
continue
ev.get()
print u'EventID={} EventName={} songs={}'.format(
ev.eventid,ev.eventname,len(ev.songlist)
)
ev.clear()
if len(args)>2:time.sleep(1)
else:
print u'Usage: dee2.py ID1 ID2 ...'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment