]> jfr.im git - irc/rizon/acid.git/blob - pyva/src/main/python/erepublik/api/feed.py
.gitignore: Ignore all pyva logs
[irc/rizon/acid.git] / pyva / src / main / python / erepublik / api / feed.py
1 import json
2 import socket
3 import urllib2
4 import xpath
5 from BaseHTTPServer import BaseHTTPRequestHandler
6 from decimal import Decimal
7 from StringIO import StringIO
8 from urlparse import urlparse
9 from xml.dom.minidom import Element
10 from xml.dom.minidom import parse
11
12 class InputError(Exception):
13 def __init__(self, msg):
14 self.msg = msg
15
16 def __str__(self):
17 return str(self.msg)
18
19 class FeedError(Exception):
20 def __init__(self, e):
21 if hasattr(e, 'code'):
22 c = e.code
23
24 if c == 404:
25 self.msg = 'not found.'
26 elif c == 406:
27 self.msg = 'this eRepublik API feed is unavailable.'
28 elif c == 500:
29 self.msg = 'eRepublik server has encountered an unexpected error.'
30 elif c == 502:
31 self.msg = 'invalid response from eRepublik server. Try again later.'
32 elif c == 503:
33 self.msg = 'eRepublik API feed is temporarily unavailable. Try again later.'
34 else:
35 self.msg = 'something went wrong while connecting to eRepublik API feed (%s)' % BaseHTTPRequestHandler.responses[e.code][0]
36
37 self.code = c
38 self.url = e.url
39 elif hasattr(e, 'reason'):
40 r = str(e.reason)
41
42 if r == 'timed out':
43 self.msg = 'connection to eRepublik API feed timed out. Try again later.'
44 else:
45 self.msg = r
46
47 self.code = None
48 self.url = None
49 else:
50 e = unicode(e)
51
52 if e == 'an error occured':
53 self.msg = 'this command cannot work because eRepublik admins disabled the API. If you want to complain, send a ticket: http://www.erepublik.com/en/tickets'
54 else:
55 self.msg = e
56
57 self.code = None
58 self.url = None
59
60 def __str__(self):
61 return self.msg
62
63 class HtmlFeed:
64 def __init__(self, value):
65 if value == None:
66 raise InputError('Invalid feed input.')
67
68 if isinstance(value, str) or isinstance(value, unicode):
69 try:
70 opener = urllib2.build_opener()
71 opener.addheaders = [('User-Agent', 'Rizon eRepublik bot - www.rizon.net')]
72 feed = opener.open(value.replace(' ', '%20'), timeout=20)
73 self._html = feed.read()
74 feed.close()
75 except urllib2.URLError, e:
76 raise FeedError(e)
77 else:
78 raise InputError('Invalid feed input type.')
79
80 def html(self):
81 return self._html
82
83 def get_json(value):
84 if value == None:
85 raise InputError('Invalid feed input.')
86
87 if isinstance(value, basestring):
88 feed = HtmlFeed(value)
89 return json.load(StringIO(feed.html()))
90 else:
91 raise InputError('Invalid feed input type.')
92
93 class XmlFeed:
94 def __init__(self, value, namespaces = None):
95 if value == None:
96 raise InputError('Invalid feed input.')
97
98 self.namespaces = {} if namespaces == None else namespaces
99
100 if isinstance(value, basestring):
101 feed = HtmlFeed(value)
102 self._element = parse(StringIO(feed.html()))
103 elif isinstance(value, Element):
104 self._element = value
105 else:
106 raise InputError('Invalid feed input type.')
107
108 error = xpath.findvalue('/error/message', self._element)
109
110 if error != None:
111 raise FeedError(error)
112
113 def elements(self, query):
114 return [XmlFeed(x, self.namespaces) for x in xpath.find(query, self._element, namespaces=self.namespaces)]
115
116 def text(self, query, default=None):
117 result = xpath.findvalue(query, self._element, namespaces=self.namespaces)
118
119 if not result:
120 value = default
121 else:
122 value = result.strip()
123
124 if isinstance(value, unicode):
125 try:
126 value = value.encode('latin-1').decode('utf-8')
127 except:
128 pass
129
130 return value
131
132 def int(self, query, default = None):
133 result = self.text(query, None)
134
135 if result == None:
136 return default
137
138 try:
139 return int(result)
140 except:
141 return default
142
143 def decimal(self, query, default = None):
144 result = self.text(query, None)
145
146 if result == None:
147 return default
148
149 try:
150 return Decimal(result)
151 except:
152 return default
153
154 def bool(self, query, default = None):
155 result = self.text(query, None)
156
157 if result == None:
158 return default
159
160 if 'true' in result.lower() or result == '1':
161 return True
162 elif 'false' in result.lower() or result == '0':
163 return False
164 else:
165 try:
166 return int(result) > 0
167 except:
168 return default