aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJinwei Zhao <[email protected]>2017-01-02 22:05:44 +0800
committerJinwei Zhao <[email protected]>2017-01-02 22:05:44 +0800
commitcb52be3055b9ef05b5d1ead9431fdd69834ee3ba (patch)
tree82447e7e18dc3e2dfc7fa32a076ee5d016e64e2b
parentcff3f50819073668391465dd8121bf9e0b8a7c33 (diff)
downloadCOMM2TG-cb52be3055b9ef05b5d1ead9431fdd69834ee3ba.tar.gz
init
-rwxr-xr-x.gitignore6
-rwxr-xr-xLICENSE21
-rwxr-xr-xbot.py289
-rwxr-xr-xconfig.json.example6
-rwxr-xr-xingrex/__init__.py4
-rwxr-xr-xingrex/intel.py144
-rwxr-xr-xingrex/praser.py25
-rwxr-xr-xingrex/utils.py80
8 files changed, 575 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100755
index 0000000..5b0c117
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
1__pycache__
2*.pyc
3*.png
4*.log
5cookie
6config.json
diff --git a/LICENSE b/LICENSE
new file mode 100755
index 0000000..03ff271
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
1The MIT License
2
3Copyright (c) 2015 Daniel
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
diff --git a/bot.py b/bot.py
new file mode 100755
index 0000000..fd3c81a
--- /dev/null
+++ b/bot.py
@@ -0,0 +1,289 @@
1# -*- coding: utf-8 -*-
2
3import os
4import re
5import time
6import json
7import logging
8import platform
9import urllib
10from selenium import webdriver
11
12import telegram
13from telegram.error import NetworkError, Unauthorized
14from pymongo import MongoClient
15
16import ingrex
17
18Debug = True
19bot = None
20BOT_TOKEN = ''
21CHANNEL_NAME = ''
22Email = ''
23Passwd = ''
24PhantomjsPath = ''
25
26LOG_FILENAME = 'voh.log'
27logging.basicConfig(level = logging.DEBUG,
28 filename = LOG_FILENAME,
29 filemode='w')
30console = logging.StreamHandler()
31console.setLevel(logging.INFO)
32# set a format which is simpler for console use
33formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
34# tell the handler to use this format
35console.setFormatter(formatter)
36# add the handler to the root logger
37logging.getLogger('').addHandler(console)
38
39class CookieException(Exception):
40 ''' CookieError '''
41
42def getTime():
43 return time.strftime('%x %X %Z')
44
45def readConfig():
46 global Email
47 global Passwd
48 global BOT_TOKEN
49 global CHANNEL_NAME
50 global PhantomjsPath
51
52 configfile = open("./config.json")
53 config = json.load(configfile)
54 Email = config["Email"]
55 Passwd = config["Passwd"]
56 BOT_TOKEN = config["BOT_TOKEN"]
57 CHANNEL_NAME = config["CHANNEL_NAME"]
58
59 osname = platform.system()
60 if osname == "Windows":
61 PhantomjsPath = 'C:\\Users\\LuciaHydrion\\AppData\\Roaming\\npm\\phantomjs.cmd'
62 elif osname == "Linux":
63 PhantomjsPath = '/home/clarkzjw/code/phantomjs-2.1.1-linux-i686/bin/phantomjs'
64 os.environ['TZ'] = 'Asia/Shanghai'
65 time.tzset()
66
67def fetchCookie():
68 global Debug
69 global Email
70 global Passwd
71 global PhantomjsPath
72
73 logger = logging.getLogger('fetchCookie')
74 logger.info(getTime() + ': Fetching Cookie...')
75
76 driver = webdriver.PhantomJS(PhantomjsPath)
77 driver.get('https://www.ingress.com/intel')
78
79 # get login page
80 link = driver.find_elements_by_tag_name('a')[0].get_attribute('href')
81 driver.get(link)
82 if Debug:
83 driver.get_screenshot_as_file('1.png')
84 # simulate manual login
85 driver.set_page_load_timeout(10)
86 driver.set_script_timeout(20)
87 driver.find_element_by_id('Email').send_keys(Email)
88 if Debug:
89 driver.get_screenshot_as_file('2.png')
90 driver.find_element_by_css_selector('#next').click()
91 time.sleep(3)
92 driver.find_element_by_id('Passwd').send_keys(Passwd)
93 if Debug:
94 driver.get_screenshot_as_file('3.png')
95 driver.find_element_by_css_selector('#signIn').click()
96 time.sleep(3)
97 if Debug:
98 driver.get_screenshot_as_file('3.png')
99 # get cookies
100 temp = driver.get_cookies()
101
102 csrftoken = ''
103 SACSID = ''
104 for a in temp:
105 if (a['name'] == 'csrftoken'):
106 csrftoken = a['value']
107 if (a['name'] == 'SACSID'):
108 SACSID = a['value']
109
110 if csrftoken == '' or SACSID == '':
111 logger.error(getTime() + ': Fetch Cookie Failed')
112 raise CookieException
113
114 with open('cookie', 'w') as file:
115 cookie = 'SACSID='+SACSID+'; csrftoken='+csrftoken+'; ingress.intelmap.shflt=viz; ingress.intelmap.lat=29.098418372855484; ingress.intelmap.lng=119.81689453125; ingress.intelmap.zoom=17'
116 file.write(cookie)
117
118 driver.quit()
119 logger.info(getTime() + ': Fetching Cookie Succeed')
120 return True
121
122def sendMessge(bot, msg):
123 "sendMsg"
124
125 logger = logging.getLogger('sendMessage')
126 while True:
127 try:
128 url = 'https://api.telegram.org/bot'
129 url += BOT_TOKEN
130 url += '/sendMessage?chat_id='
131 url += CHANNEL_NAME
132 url += '&text='
133 url += urllib.parse.quote(msg)
134
135 req = urllib.request.Request(url, headers={'Content-Type': 'application/x-www-form-urlencoded'})
136 resp = urllib.request.urlopen(req)
137 data = resp.read()
138
139 #bot.sendMessage(chat_id=CHANNEL_NAME, text=msg)
140 logger.info(getTime() + ": sendMsg " + msg)
141 break
142 except NetworkError:
143 time.sleep(1)
144
145def sendMonitor(bot, msg):
146 logger = logging.getLogger('sendMonitor')
147 while True:
148 try:
149 bot.sendMessage(chat_id="@voamonitor", text=msg)
150 logger.info(getTime() + ": sendMsg " + msg)
151 break
152 except NetworkError:
153 time.sleep(1)
154
155def formatMessage(raw):
156 pattern = re.compile('xmps.biz|enl.sh|ingressfarm.com|Polygon')
157 match = pattern.search(str(raw))
158 if match:
159 return "Blocked"
160
161 msg = ''
162 plext = raw[2]['plext']
163 markup = plext['markup']
164 plaintext = plext['text']
165
166 for mark in markup:
167 if mark[0] == 'SECURE':
168 msg += mark[1]['plain']
169 elif mark[0] == 'SENDER':
170 player = mark[1]['plain']
171 team = mark[1]['team']
172
173 pattern = re.compile(':')
174 match = pattern.search(player)
175 if match:
176 if team == 'RESISTANCE':
177 player = player[:match.span()[0]] + ' 🐳' + player[match.span()[0]:]
178 elif team == 'ENLIGHTENED':
179 player = player[:match.span()[0]] + ' 🐸' + player[match.span()[0]:]
180 msg += player
181
182 elif mark[0] == 'PLAYER' or mark[0] == 'AT_PLAYER':
183 player = mark[1]['plain']
184 team = mark[1]['team']
185
186 msg += player
187 if team == 'RESISTANCE':
188 msg += ' 🐳'
189 elif team == 'ENLIGHTENED':
190 msg += ' 🐸'
191
192 elif mark[0] == 'TEXT':
193 msg += mark[1]['plain']
194
195 pattern = re.compile('\[secure\]')
196 match = pattern.search(msg)
197 if match:
198 if msg.find(':') != -1:
199 msg = msg[:9] + '@' + msg[9:]
200 else:
201 msg = msg[:10] + '@' + msg[10:]
202 else:
203 msg = '@' + msg
204
205 return msg
206
207def insertDB(time, msg):
208 logger = logging.getLogger('insertDB')
209 Conn = MongoClient()
210 database = Conn['COMM_Hangzhou']
211 mycollection = database.entries
212 post = {"time": time, "msg": msg}
213 mycollection.insert(post)
214
215
216def main():
217 logger = logging.getLogger('main')
218
219 field = {
220 'minLngE6':119618783,
221 'minLatE6':29912919,
222 'maxLngE6':121018722,
223 'maxLatE6':30573739,
224 }
225
226 mints = -1
227 maxts=-1
228 reverse=False
229 tab='all'
230
231 while True:
232 try:
233 if fetchCookie():
234 break
235 except CookieException:
236 time.sleep(3)
237
238 count = 0
239 while True:
240 count += 1
241
242 with open('cookie') as cookies:
243 cookies = cookies.read().strip()
244
245 logger.info(getTime() + ": {} Fetching from Intel...".format(str(count)))
246
247 while True:
248 try:
249
250 intel = ingrex.Intel(cookies, field)
251 result = intel.fetch_msg(mints, maxts, reverse, tab)
252
253 if result:
254 mints = result[0][1] + 1
255 break
256 except CookieError:
257 while True:
258 try:
259 if fetchCookie():
260 break
261 except CookieException:
262 time.sleep(3)
263
264 for item in result[::-1]:
265 message = ingrex.Message(item)
266 if message.ptype == 'PLAYER_GENERATED':
267 logger.info(getTime() + str(item))
268
269 msg = formatMessage(item)
270 if msg == 'Blocked':
271 logger.info(getTime() + " " + message.text)
272 else:
273 msg = message.time + " " + msg
274 logger.info(getTime() + " " + msg)
275 insertDB(message.time, msg)
276 sendMonitor(bot, msg)
277 #sendMessge(bot, msg)
278
279 time.sleep(10)
280
281if __name__ == '__main__':
282 readConfig()
283 bot = telegram.Bot(BOT_TOKEN)
284
285 while True:
286 try:
287 main()
288 except Exception:
289 sendMonitor(bot, 'Main Error')
diff --git a/config.json.example b/config.json.example
new file mode 100755
index 0000000..c048ee9
--- /dev/null
+++ b/config.json.example
@@ -0,0 +1,6 @@
1{
2 "Email": "Your Ingress Account Email",
3 "Passwd": "Your Ingress Account Password",
4 "BOT_TOKEN": "Your Telegram Bot Token",
5 "CHANNEL_NAME": "Your Channel ID"
6}
diff --git a/ingrex/__init__.py b/ingrex/__init__.py
new file mode 100755
index 0000000..91876bf
--- /dev/null
+++ b/ingrex/__init__.py
@@ -0,0 +1,4 @@
1"Init"
2from . intel import Intel
3from . praser import Message
4from . import utils as Utils
diff --git a/ingrex/intel.py b/ingrex/intel.py
new file mode 100755
index 0000000..f13b2a2
--- /dev/null
+++ b/ingrex/intel.py
@@ -0,0 +1,144 @@
1"Ingrex is a python lib for ingress"
2import requests
3import re
4import json
5import os
6
7class Intel(object):
8 "main class with all Intel functions"
9
10 def __init__(self, cookies, field):
11 self.DEBUG = True
12 token = re.findall(r'csrftoken=(\w*);', cookies)[0]
13 self.headers = {
14 'accept-encoding': 'gzip, deflate',
15 'content-type': 'application/json; charset=UTF-8',
16 'cookie': cookies,
17 'origin': 'https://www.ingress.com',
18 'referer': 'https://www.ingress.com/intel',
19 'user-agent': 'Mozilla/5.0 (MSIE 9.0; Windows NT 6.1; Trident/5.0)',
20 'x-csrftoken': token,
21 }
22 self.field = {
23 'maxLatE6': field['maxLatE6'],
24 'minLatE6': field['minLatE6'],
25 'maxLngE6': field['maxLngE6'],
26 'minLngE6': field['minLngE6'],
27 }
28 self.point = {
29 'latE6': (field['maxLatE6'] + field['minLatE6']) >> 1,
30 'lngE6': (field['maxLngE6'] + field['minLngE6']) >> 1,
31 }
32 self.session = requests.session()
33 self.refresh_version()
34
35 def refresh_version(self):
36 "refresh api version for request"
37 request = self.session.get('https://www.ingress.com/intel', headers=self.headers)
38 self.version = re.findall(r'gen_dashboard_(\w*)\.js', request.text)[0]
39
40 def fetch(self, url, payload):
41 "raw request with auto-retry and connection check function"
42 payload['v'] = self.version
43 count = 0
44 while count < 3:
45 try:
46 request = self.session.post(url, data=json.dumps(payload), headers=self.headers)
47 return request.json()['result']
48 except requests.ConnectionError:
49 raise IntelError
50 except Exception:
51 count += 1
52 continue
53 raise CookieError
54
55 def fetch_msg(self, mints=-1, maxts=-1, reverse=False, tab='all'):
56 "fetch message from Ingress COMM, tab can be 'all', 'faction', 'alerts'"
57 url = 'https://www.ingress.com/r/getPlexts'
58 payload = {
59 'maxLatE6': self.field['maxLatE6'],
60 'minLatE6': self.field['minLatE6'],
61 'maxLngE6': self.field['maxLngE6'],
62 'minLngE6': self.field['minLngE6'],
63 'maxTimestampMs': maxts,
64 'minTimestampMs': mints,
65 'tab': tab
66 }
67 if reverse:
68 payload['ascendingTimestampOrder'] = True
69 return self.fetch(url, payload)
70
71 def fetch_map(self, tilekeys):
72 "fetch game entities from Ingress map"
73 url = 'https://www.ingress.com/r/getEntities'
74 payload = {
75 'tileKeys': tilekeys
76 }
77 return self.fetch(url, payload)
78
79 def fetch_portal(self, guid):
80 "fetch portal details from Ingress"
81 url = 'https://www.ingress.com/r/getPortalDetails'
82 payload = {
83 'guid': guid
84 }
85 return self.fetch(url, payload)
86
87 def fetch_score(self):
88 "fetch the global score of RESISTANCE and ENLIGHTENED"
89 url = 'https://www.ingress.com/r/getGameScore'
90 payload = {}
91 return self.fetch(url, payload)
92
93 def fetch_region(self):
94 "fetch the region info of RESISTANCE and ENLIGHTENED"
95 url = 'https://www.ingress.com/r/getRegionScoreDetails'
96 payload = {
97 'lngE6': self.point['lngE6'],
98 'latE6': self.point['latE6'],
99 }
100 return self.fetch(url, payload)
101
102 def fetch_artifacts(self):
103 "fetch the artifacts details"
104 url = 'https://www.ingress.com/r/getArtifactPortals'
105 payload = {}
106 return self.fetch(url, payload)
107
108 def send_msg(self, msg, tab='all'):
109 "send a message to Ingress COMM, tab can be 'all', 'faction'"
110 url = 'https://www.ingress.com/r/sendPlext'
111 payload = {
112 'message': msg,
113 'latE6': self.point['latE6'],
114 'lngE6': self.point['lngE6'],
115 'tab': tab
116 }
117 return self.fetch(url, payload)
118
119 def send_invite(self, address):
120 "send a recruit to an email address"
121 url = 'https://www.ingress.com/r/sendInviteEmail'
122 payload = {
123 'inviteeEmailAddress': address
124 }
125 return self.fetch(url, payload)
126
127 def redeem_code(self, passcode):
128 "redeem a passcode"
129 url = 'https://www.ingress.com/r/redeemReward'
130 payload = {
131 'passcode': passcode
132 }
133 return self.fetch(url, payload)
134
135class IntelError(BaseException):
136 """Intel Error"""
137 pass
138
139class CookieError(IntelError):
140 """Intel Error"""
141 pass
142
143if __name__ == '__main__':
144 pass
diff --git a/ingrex/praser.py b/ingrex/praser.py
new file mode 100755
index 0000000..732ab1b
--- /dev/null
+++ b/ingrex/praser.py
@@ -0,0 +1,25 @@
1"Ingrex praser deal with message"
2from datetime import datetime, timedelta
3import platform
4import os
5import time
6
7osname = platform.system()
8if osname == "Linux":
9 os.environ['TZ'] = 'Asia/Shanghai'
10 time.tzset()
11
12class Message(object):
13 "Message object"
14 def __init__(self, raw_msg):
15 self.raw = raw_msg
16 self.guid = raw_msg[0]
17 self.timestamp = raw_msg[1]
18 seconds, millis = divmod(raw_msg[1], 1000)
19 time = datetime.fromtimestamp(seconds) + timedelta(milliseconds=millis)
20 self.time = time.strftime('%Y/%m/%d %H:%M:%S:%f')[:-3]
21 self.text = raw_msg[2]['plext']['text']
22 self.ptype = raw_msg[2]['plext']['plextType']
23 self.team = raw_msg[2]['plext']['team']
24 self.type = raw_msg[2]['plext']['markup'][1][1]['plain']
25
diff --git a/ingrex/utils.py b/ingrex/utils.py
new file mode 100755
index 0000000..8090f15
--- /dev/null
+++ b/ingrex/utils.py
@@ -0,0 +1,80 @@
1"Map Utils"
2from math import pi, sin, cos, tan, asin, radians, sqrt, log
3
4def calc_tile(lng, lat, zoomlevel):
5 tilecounts = [1,1,1,40,40,80,80,320,1E3,2E3,2E3,4E3,8E3,16E3,16E3,32E3]
6 rlat = radians(lat)
7 tilecount = tilecounts[zoomlevel]
8 xtile = int((lng + 180.0) / 360.0 * tilecount)
9 ytile = int((1.0 - log(tan(rlat) + (1 / cos(rlat))) / pi) / 2.0 * tilecount)
10 return xtile, ytile
11
12def calc_dist(lat1, lng1, lat2, lng2):
13 lat1, lng1, lat2, lng2 = map(radians, [lat1, lng1, lat2, lng2])
14 dlat = lat1 - lat2
15 dlng = lng1 - lng2
16 a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlng/2)**2
17 c = 2* asin(sqrt(a))
18 m = 6367.0 * c * 1000
19 return m
20
21def point_in_poly(x, y, poly):
22 n = len(poly)
23 inside = False
24 p1x,p1y = poly[0]
25 for i in range(n+1):
26 p2x,p2y = poly[i % n]
27 if y > min(p1y, p2y):
28 if y <= max(p1y, p2y):
29 if x <= max(p1x, p2x):
30 if p1y != p2y:
31 xints = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
32 if p1x == p2x or x <= xints:
33 inside = not inside
34 p1x,p1y = p2x,p2y
35 return inside
36
37def transform(wgLat, wgLon):
38 """
39 transform(latitude,longitude) , WGS84
40 return (latitude,longitude) , GCJ02
41 """
42 a = 6378245.0
43 ee = 0.00669342162296594323
44 if (outOfChina(wgLat, wgLon)):
45 mgLat = wgLat
46 mgLon = wgLon
47 return mgLat,mgLon
48 dLat = transformLat(wgLon - 105.0, wgLat - 35.0)
49 dLon = transformLon(wgLon - 105.0, wgLat - 35.0)
50 radLat = wgLat / 180.0 * pi
51 magic = sin(radLat)
52 magic = 1 - ee * magic * magic
53 sqrtMagic = sqrt(magic)
54 dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi)
55 dLon = (dLon * 180.0) / (a / sqrtMagic * cos(radLat) * pi)
56 mgLat = wgLat + dLat
57 mgLon = wgLon + dLon
58 return mgLat,mgLon
59
60def outOfChina(lat, lon):
61 if (lon < 72.004 or lon > 137.8347):
62 return True
63 if (lat < 0.8293 or lat > 55.8271):
64 return True
65 return False
66
67def transformLat(x, y):
68 ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(abs(x))
69 ret += (20.0 * sin(6.0 * x * pi) + 20.0 * sin(2.0 * x * pi)) * 2.0 / 3.0
70 ret += (20.0 * sin(y * pi) + 40.0 * sin(y / 3.0 * pi)) * 2.0 / 3.0
71 ret += (160.0 * sin(y / 12.0 * pi) + 320 * sin(y * pi / 30.0)) * 2.0 / 3.0
72 return ret
73
74def transformLon(x, y):
75 ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(abs(x))
76 ret += (20.0 * sin(6.0 * x * pi) + 20.0 * sin(2.0 * x * pi)) * 2.0 / 3.0
77 ret += (20.0 * sin(x * pi) + 40.0 * sin(x / 3.0 * pi)) * 2.0 / 3.0
78 ret += (150.0 * sin(x / 12.0 * pi) + 300.0 * sin(x / 30.0 * pi)) * 2.0 / 3.0
79 return ret
80
Powered by cgit v1.2.3 (git 2.41.0)