Advertisement
Guest User

Untitled

a guest
Jul 19th, 2016
148
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 29.34 KB | None | 0 0
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3.  
  4. import flask
  5. from flask import Flask, render_template
  6. from flask_googlemaps import GoogleMaps
  7. from flask_googlemaps import Map
  8. from flask_googlemaps import icons
  9. import os
  10. import re
  11. import sys
  12. import struct
  13. import json
  14. import requests
  15. import argparse
  16. import getpass
  17. import threading
  18. import werkzeug.serving
  19. import pokemon_pb2
  20. import time
  21. from google.protobuf.internal import encoder
  22. from google.protobuf.message import DecodeError
  23. from s2sphere import *
  24. from datetime import datetime
  25. from geopy.geocoders import GoogleV3
  26. from gpsoauth import perform_master_login, perform_oauth
  27. from geopy.exc import GeocoderTimedOut, GeocoderServiceError
  28. from requests.packages.urllib3.exceptions import InsecureRequestWarning
  29. from requests.adapters import ConnectionError
  30. from requests.models import InvalidURL
  31. from transform import *
  32.  
  33. requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
  34.  
  35. API_URL = 'https://pgorelease.nianticlabs.com/plfe/rpc'
  36. LOGIN_URL = \
  37. 'https://sso.pokemon.com/sso/login?service=https://sso.pokemon.com/sso/oauth2.0/callbackAuthorize'
  38. LOGIN_OAUTH = 'https://sso.pokemon.com/sso/oauth2.0/accessToken'
  39. APP = 'com.nianticlabs.pokemongo'
  40.  
  41. with open('credentials.json') as file:
  42. credentials = json.load(file)
  43.  
  44. PTC_CLIENT_SECRET = credentials.get('ptc_client_secret', None)
  45. ANDROID_ID = credentials.get('android_id', None)
  46. SERVICE = credentials.get('service', None)
  47. CLIENT_SIG = credentials.get('client_sig', None)
  48. GOOGLEMAPS_KEY = credentials.get('gmaps_key', None)
  49.  
  50. SESSION = requests.session()
  51. SESSION.headers.update({'User-Agent': 'Niantic App'})
  52. SESSION.verify = False
  53.  
  54. global_password = None
  55. global_token = None
  56. access_token = None
  57. DEBUG = True
  58. VERBOSE_DEBUG = False # if you want to write raw request/response to the console
  59. COORDS_LATITUDE = 0
  60. COORDS_LONGITUDE = 0
  61. COORDS_ALTITUDE = 0
  62. FLOAT_LAT = 0
  63. FLOAT_LONG = 0
  64. NEXT_LAT = 0
  65. NEXT_LONG = 0
  66. auto_refresh = 0
  67. default_step = 0.001
  68. api_endpoint = None
  69. pokemons = {}
  70. gyms = {}
  71. pokestops = {}
  72. numbertoteam = { # At least I'm pretty sure that's it. I could be wrong and then I'd be displaying the wrong owner team of gyms.
  73. 0: 'Gym',
  74. 1: 'Mystic',
  75. 2: 'Valor',
  76. 3: 'Instinct',
  77. }
  78. origin_lat, origin_lon = None, None
  79. is_ampm_clock = False
  80.  
  81. # stuff for in-background search thread
  82.  
  83. search_thread = None
  84.  
  85. def memoize(obj):
  86. cache = obj.cache = {}
  87.  
  88. @functools.wraps(obj)
  89. def memoizer(*args, **kwargs):
  90. key = str(args) + str(kwargs)
  91. if key not in cache:
  92. cache[key] = obj(*args, **kwargs)
  93. return cache[key]
  94. return memoizer
  95.  
  96. def parse_unicode(bytestring):
  97. decoded_string = bytestring.decode(sys.getfilesystemencoding())
  98. return decoded_string
  99.  
  100.  
  101. def debug(message):
  102. if DEBUG:
  103. print '[-] {}'.format(message)
  104.  
  105.  
  106. def time_left(ms):
  107. s = ms / 1000
  108. (m, s) = divmod(s, 60)
  109. (h, m) = divmod(m, 60)
  110. return (h, m, s)
  111.  
  112.  
  113. def encode(cellid):
  114. output = []
  115. encoder._VarintEncoder()(output.append, cellid)
  116. return ''.join(output)
  117.  
  118.  
  119. def getNeighbors():
  120. origin = CellId.from_lat_lng(LatLng.from_degrees(FLOAT_LAT,
  121. FLOAT_LONG)).parent(15)
  122. walk = [origin.id()]
  123.  
  124. # 10 before and 10 after
  125.  
  126. next = origin.next()
  127. prev = origin.prev()
  128. for i in range(10):
  129. walk.append(prev.id())
  130. walk.append(next.id())
  131. next = next.next()
  132. prev = prev.prev()
  133. return walk
  134.  
  135.  
  136. def f2i(float):
  137. return struct.unpack('<Q', struct.pack('<d', float))[0]
  138.  
  139.  
  140. def f2h(float):
  141. return hex(struct.unpack('<Q', struct.pack('<d', float))[0])
  142.  
  143.  
  144. def h2f(hex):
  145. return struct.unpack('<d', struct.pack('<Q', int(hex, 16)))[0]
  146.  
  147.  
  148. def retrying_set_location(location_name):
  149. """
  150. Continue trying to get co-ords from Google Location until we have them
  151. :param location_name: string to pass to Location API
  152. :return: None
  153. """
  154.  
  155. while True:
  156. try:
  157. set_location(location_name)
  158. return
  159. except (GeocoderTimedOut, GeocoderServiceError), e:
  160. debug(
  161. 'retrying_set_location: geocoder exception ({}), retrying'.format(
  162. str(e)))
  163. time.sleep(1.25)
  164.  
  165.  
  166. def set_location(location_name):
  167. geolocator = GoogleV3()
  168. prog = re.compile('^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$')
  169. global origin_lat
  170. global origin_lon
  171. if prog.match(location_name):
  172. local_lat, local_lng = [float(x) for x in location_name.split(",")]
  173. alt = 0
  174. origin_lat, origin_lon = local_lat, local_lng
  175. else:
  176. loc = geolocator.geocode(location_name)
  177. origin_lat, origin_lon = local_lat, local_lng = loc.latitude, loc.longitude
  178. alt = loc.altitude
  179. print '[!] Your given location: {}'.format(loc.address.encode('utf-8'))
  180.  
  181. print('[!] lat/long/alt: {} {} {}'.format(local_lat, local_lng, alt))
  182. set_location_coords(local_lat, local_lng, alt)
  183.  
  184.  
  185. def set_location_coords(lat, long, alt):
  186. global COORDS_LATITUDE, COORDS_LONGITUDE, COORDS_ALTITUDE
  187. global FLOAT_LAT, FLOAT_LONG
  188. FLOAT_LAT = lat
  189. FLOAT_LONG = long
  190. COORDS_LATITUDE = f2i(lat) # 0x4042bd7c00000000 # f2i(lat)
  191. COORDS_LONGITUDE = f2i(long) # 0xc05e8aae40000000 #f2i(long)
  192. COORDS_ALTITUDE = f2i(alt)
  193.  
  194.  
  195. def get_location_coords():
  196. return (COORDS_LATITUDE, COORDS_LONGITUDE, COORDS_ALTITUDE)
  197.  
  198.  
  199. def retrying_api_req(service, api_endpoint, access_token, *args, **kwargs):
  200. while True:
  201. try:
  202. response = api_req(service, api_endpoint, access_token, *args,
  203. **kwargs)
  204. if response:
  205. return response
  206. debug('retrying_api_req: api_req returned None, retrying')
  207. except (InvalidURL, ConnectionError, DecodeError), e:
  208. debug('retrying_api_req: request error ({}), retrying'.format(
  209. str(e)))
  210. time.sleep(1)
  211.  
  212.  
  213. def api_req(service, api_endpoint, access_token, *args, **kwargs):
  214. p_req = pokemon_pb2.RequestEnvelop()
  215. p_req.rpc_id = 1469378659230941192
  216.  
  217. p_req.unknown1 = 2
  218.  
  219. (p_req.latitude, p_req.longitude, p_req.altitude) = \
  220. get_location_coords()
  221.  
  222. p_req.unknown12 = 989
  223.  
  224. if 'useauth' not in kwargs or not kwargs['useauth']:
  225. p_req.auth.provider = service
  226. p_req.auth.token.contents = access_token
  227. p_req.auth.token.unknown13 = 14
  228. else:
  229. p_req.unknown11.unknown71 = kwargs['useauth'].unknown71
  230. p_req.unknown11.unknown72 = kwargs['useauth'].unknown72
  231. p_req.unknown11.unknown73 = kwargs['useauth'].unknown73
  232.  
  233. for arg in args:
  234. p_req.MergeFrom(arg)
  235.  
  236. protobuf = p_req.SerializeToString()
  237.  
  238. r = SESSION.post(api_endpoint, data=protobuf, verify=False)
  239.  
  240. p_ret = pokemon_pb2.ResponseEnvelop()
  241. p_ret.ParseFromString(r.content)
  242.  
  243. if VERBOSE_DEBUG:
  244. print 'REQUEST:'
  245. print p_req
  246. print 'Response:'
  247. print p_ret
  248. print '''
  249.  
  250. '''
  251. time.sleep(0.51)
  252. return p_ret
  253.  
  254.  
  255. def get_api_endpoint(service, access_token, api=API_URL):
  256. profile_response = None
  257. while not profile_response:
  258. profile_response = retrying_get_profile(service, access_token, api,
  259. None)
  260. if not hasattr(profile_response, 'api_url'):
  261. debug(
  262. 'retrying_get_profile: get_profile returned no api_url, retrying')
  263. profile_response = None
  264. continue
  265. if not len(profile_response.api_url):
  266. debug(
  267. 'get_api_endpoint: retrying_get_profile returned no-len api_url, retrying')
  268. profile_response = None
  269.  
  270. return 'https://%s/rpc' % profile_response.api_url
  271.  
  272. def retrying_get_profile(service, access_token, api, useauth, *reqq):
  273. profile_response = None
  274. while not profile_response:
  275. profile_response = get_profile(service, access_token, api, useauth,
  276. *reqq)
  277. if not hasattr(profile_response, 'payload'):
  278. debug(
  279. 'retrying_get_profile: get_profile returned no payload, retrying')
  280. profile_response = None
  281. continue
  282. if not profile_response.payload:
  283. debug(
  284. 'retrying_get_profile: get_profile returned no-len payload, retrying')
  285. profile_response = None
  286.  
  287. return profile_response
  288.  
  289. def get_profile(service, access_token, api, useauth, *reqq):
  290. req = pokemon_pb2.RequestEnvelop()
  291. req1 = req.requests.add()
  292. req1.type = 2
  293. if len(reqq) >= 1:
  294. req1.MergeFrom(reqq[0])
  295.  
  296. req2 = req.requests.add()
  297. req2.type = 126
  298. if len(reqq) >= 2:
  299. req2.MergeFrom(reqq[1])
  300.  
  301. req3 = req.requests.add()
  302. req3.type = 4
  303. if len(reqq) >= 3:
  304. req3.MergeFrom(reqq[2])
  305.  
  306. req4 = req.requests.add()
  307. req4.type = 129
  308. if len(reqq) >= 4:
  309. req4.MergeFrom(reqq[3])
  310.  
  311. req5 = req.requests.add()
  312. req5.type = 5
  313. if len(reqq) >= 5:
  314. req5.MergeFrom(reqq[4])
  315. return retrying_api_req(service, api, access_token, req, useauth=useauth)
  316.  
  317. def login_google(username, password):
  318. print '[!] Google login for: {}'.format(username)
  319. r1 = perform_master_login(username, password, ANDROID_ID)
  320. r2 = perform_oauth(username,
  321. r1.get('Token', ''),
  322. ANDROID_ID,
  323. SERVICE,
  324. APP,
  325. CLIENT_SIG, )
  326. return r2.get('Auth')
  327.  
  328. def login_ptc(username, password):
  329. print '[!] PTC login for: {}'.format(username)
  330. head = {'User-Agent': 'Niantic App'}
  331. r = SESSION.get(LOGIN_URL, headers=head)
  332. if r is None:
  333. return render_template('nope.html', fullmap=fullmap)
  334.  
  335. try:
  336. jdata = json.loads(r.content)
  337. except ValueError, e:
  338. debug('login_ptc: could not decode JSON from {}'.format(r.content))
  339. return None
  340.  
  341. # Maximum password length is 15 (sign in page enforces this limit, API does not)
  342.  
  343. if len(password) > 15:
  344. print '[!] Trimming password to 15 characters'
  345. password = password[:15]
  346.  
  347. data = {
  348. 'lt': jdata['lt'],
  349. 'execution': jdata['execution'],
  350. '_eventId': 'submit',
  351. 'username': username,
  352. 'password': password,
  353. }
  354. r1 = SESSION.post(LOGIN_URL, data=data, headers=head)
  355.  
  356. ticket = None
  357. try:
  358. ticket = re.sub('.*ticket=', '', r1.history[0].headers['Location'])
  359. except Exception, e:
  360. if DEBUG:
  361. print r1.json()['errors'][0]
  362. return None
  363.  
  364. data1 = {
  365. 'client_id': 'mobile-app_pokemon-go',
  366. 'redirect_uri': 'https://www.nianticlabs.com/pokemongo/error',
  367. 'client_secret': PTC_CLIENT_SECRET,
  368. 'grant_type': 'refresh_token',
  369. 'code': ticket,
  370. }
  371. r2 = SESSION.post(LOGIN_OAUTH, data=data1)
  372. access_token = re.sub('&expires.*', '', r2.content)
  373. access_token = re.sub('.*access_token=', '', access_token)
  374.  
  375. return access_token
  376.  
  377.  
  378. def get_heartbeat(service,
  379. api_endpoint,
  380. access_token,
  381. response, ):
  382. m4 = pokemon_pb2.RequestEnvelop.Requests()
  383. m = pokemon_pb2.RequestEnvelop.MessageSingleInt()
  384. m.f1 = int(time.time() * 1000)
  385. m4.message = m.SerializeToString()
  386. m5 = pokemon_pb2.RequestEnvelop.Requests()
  387. m = pokemon_pb2.RequestEnvelop.MessageSingleString()
  388. m.bytes = '05daf51635c82611d1aac95c0b051d3ec088a930'
  389. m5.message = m.SerializeToString()
  390. walk = sorted(getNeighbors())
  391. m1 = pokemon_pb2.RequestEnvelop.Requests()
  392. m1.type = 106
  393. m = pokemon_pb2.RequestEnvelop.MessageQuad()
  394. m.f1 = ''.join(map(encode, walk))
  395. m.f2 = \
  396. "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
  397. m.lat = COORDS_LATITUDE
  398. m.long = COORDS_LONGITUDE
  399. m1.message = m.SerializeToString()
  400. response = get_profile(service,
  401. access_token,
  402. api_endpoint,
  403. response.unknown7,
  404. m1,
  405. pokemon_pb2.RequestEnvelop.Requests(),
  406. m4,
  407. pokemon_pb2.RequestEnvelop.Requests(),
  408. m5, )
  409.  
  410. try:
  411. payload = response.payload[0]
  412. except (AttributeError, IndexError):
  413. return
  414.  
  415. heartbeat = pokemon_pb2.ResponseEnvelop.HeartbeatPayload()
  416. heartbeat.ParseFromString(payload)
  417. return heartbeat
  418.  
  419. def get_token(service, username, password):
  420. """
  421. Get token if it's not None
  422. :return:
  423. :rtype:
  424. """
  425.  
  426. global global_token
  427. if global_token is None:
  428. if service == 'ptc':
  429. global_token = login_ptc(username, password)
  430. else:
  431. global_token = login_google(username, password)
  432. return global_token
  433. else:
  434. return global_token
  435.  
  436.  
  437. def get_args():
  438. parser = argparse.ArgumentParser()
  439. parser.add_argument(
  440. '-a', '--auth_service', type=str.lower, help='Auth Service', default='ptc')
  441. parser.add_argument('-u', '--username', help='Username', required=True)
  442. parser.add_argument('-p', '--password', help='Password', required=False)
  443. parser.add_argument(
  444. '-l', '--location', type=parse_unicode, help='Location', required=True)
  445. parser.add_argument('-st', '--step-limit', help='Steps', required=True)
  446. group = parser.add_mutually_exclusive_group(required=False)
  447. group.add_argument(
  448. '-i', '--ignore', help='Comma-separated list of Pokémon names to ignore')
  449. group.add_argument(
  450. '-o', '--only', help='Comma-separated list of Pokémon names to search')
  451. parser.add_argument(
  452. "-ar",
  453. "--auto_refresh",
  454. help="Enables an autorefresh that behaves the same as a page reload. " +
  455. "Needs an integer value for the amount of seconds")
  456. parser.add_argument(
  457. '-dp',
  458. '--display-pokestop',
  459. help='Display pokéstop',
  460. action='store_true',
  461. default=False)
  462. parser.add_argument(
  463. '-dg',
  464. '--display-gym',
  465. help='Display Gym',
  466. action='store_true',
  467. default=False)
  468. parser.add_argument(
  469. '-H',
  470. '--host',
  471. help='Set web server listening host',
  472. default='127.0.0.1')
  473. parser.add_argument(
  474. '-P',
  475. '--port',
  476. type=int,
  477. help='Set web server listening port',
  478. default=5000)
  479. parser.add_argument(
  480. "-L",
  481. "--locale",
  482. help="Locale for Pokemon names: default en, check locale folder for more options",
  483. default="en")
  484. parser.add_argument(
  485. "-ol",
  486. "--onlylure",
  487. help='Display only lured pokéstop',
  488. action='store_true')
  489. parser.add_argument(
  490. '-c',
  491. '--china',
  492. help='Coordinates transformer for China',
  493. action='store_true')
  494. parser.add_argument(
  495. "-pm",
  496. "--ampm_clock",
  497. help="Toggles the AM/PM clock for Pokemon timers",
  498. action='store_true',
  499. default=False)
  500. parser.add_argument(
  501. '-d', '--debug', help='Debug Mode', action='store_true')
  502. parser.set_defaults(DEBUG=True)
  503. return parser.parse_args()
  504.  
  505. @memoize
  506. def login(args):
  507. global global_password
  508. if not global_password:
  509. if args.password:
  510. global_password = args.password
  511. else:
  512. global_password = getpass.getpass()
  513.  
  514. access_token = get_token(args.auth_service, args.username, global_password)
  515. if access_token is None:
  516. raise Exception('[-] Wrong username/password')
  517.  
  518. print '[+] RPC Session Token: {} ...'.format(access_token[:25])
  519.  
  520. api_endpoint = get_api_endpoint(args.auth_service, access_token)
  521. if api_endpoint is None:
  522. raise Exception('[-] RPC server offline')
  523.  
  524. print '[+] Received API endpoint: {}'.format(api_endpoint)
  525.  
  526. profile_response = retrying_get_profile(args.auth_service, access_token,
  527. api_endpoint, None)
  528. if profile_response is None or not profile_response.payload:
  529. raise Exception('Could not get profile')
  530.  
  531. print '[+] Login successful'
  532.  
  533. payload = profile_response.payload[0]
  534. profile = pokemon_pb2.ResponseEnvelop.ProfilePayload()
  535. profile.ParseFromString(payload)
  536. print '[+] Username: {}'.format(profile.profile.username)
  537.  
  538. creation_time = \
  539. datetime.fromtimestamp(int(profile.profile.creation_time)
  540. / 1000)
  541. print '[+] You started playing Pokemon Go on: {}'.format(
  542. creation_time.strftime('%Y-%m-%d %H:%M:%S'))
  543.  
  544. for curr in profile.profile.currency:
  545. print '[+] {}: {}'.format(curr.type, curr.amount)
  546.  
  547. return api_endpoint, access_token, profile_response
  548.  
  549. def main():
  550. full_path = os.path.realpath(__file__)
  551. (path, filename) = os.path.split(full_path)
  552.  
  553. args = get_args()
  554.  
  555. if args.auth_service not in ['ptc', 'google']:
  556. print '[!] Invalid Auth service specified'
  557. return
  558.  
  559. print('[+] Locale is ' + args.locale)
  560. pokemonsJSON = json.load(
  561. open(path + '/locales/pokemon.' + args.locale + '.json'))
  562.  
  563. if args.debug:
  564. global DEBUG
  565. DEBUG = True
  566. print '[!] DEBUG mode on'
  567.  
  568. # only get location for first run
  569. if not (FLOAT_LAT and FLOAT_LONG):
  570. print('[+] Getting initial location')
  571. retrying_set_location(args.location)
  572.  
  573. if args.auto_refresh:
  574. global auto_refresh
  575. auto_refresh = int(args.auto_refresh) * 1000
  576.  
  577. if args.ampm_clock:
  578. global is_ampm_clock
  579. is_ampm_clock = True
  580.  
  581. api_endpoint, access_token, profile_response = login(args)
  582.  
  583. clear_stale_pokemons()
  584.  
  585. steplimit = int(args.step_limit)
  586.  
  587. ignore = []
  588. only = []
  589. if args.ignore:
  590. ignore = [i.lower().strip() for i in args.ignore.split(',')]
  591. elif args.only:
  592. only = [i.lower().strip() for i in args.only.split(',')]
  593.  
  594. pos = 1
  595. x = 0
  596. y = 0
  597. dx = 0
  598. dy = -1
  599. steplimit2 = steplimit**2
  600. for step in range(steplimit2):
  601. #starting at 0 index
  602. debug('looping: step {} of {}'.format((step+1), steplimit**2))
  603. #debug('steplimit: {} x: {} y: {} pos: {} dx: {} dy {}'.format(steplimit2, x, y, pos, dx, dy))
  604. # Scan location math
  605. if -steplimit2 / 2 < x <= steplimit2 / 2 and -steplimit2 / 2 < y <= steplimit2 / 2:
  606. set_location_coords(x * 0.0025 + origin_lat, y * 0.0025 + origin_lon, 0)
  607. if x == y or x < 0 and x == -y or x > 0 and x == 1 - y:
  608. (dx, dy) = (-dy, dx)
  609.  
  610. (x, y) = (x + dx, y + dy)
  611.  
  612. process_step(args, api_endpoint, access_token, profile_response,
  613. pokemonsJSON, ignore, only)
  614.  
  615. print('Completed: ' + str(
  616. ((step+1) + pos * .25 - .25) / (steplimit2) * 100) + '%')
  617.  
  618. global NEXT_LAT, NEXT_LONG
  619. if (NEXT_LAT and NEXT_LONG and
  620. (NEXT_LAT != FLOAT_LAT or NEXT_LONG != FLOAT_LONG)):
  621. print('Update to next location %f, %f' % (NEXT_LAT, NEXT_LONG))
  622. set_location_coords(NEXT_LAT, NEXT_LONG, 0)
  623. NEXT_LAT = 0
  624. NEXT_LONG = 0
  625. else:
  626. set_location_coords(origin_lat, origin_lon, 0)
  627.  
  628. register_background_thread()
  629.  
  630.  
  631. def process_step(args, api_endpoint, access_token, profile_response,
  632. pokemonsJSON, ignore, only):
  633. print('[+] Searching for Pokemon at location {} {}'.format(FLOAT_LAT, FLOAT_LONG))
  634. origin = LatLng.from_degrees(FLOAT_LAT, FLOAT_LONG)
  635. step_lat = FLOAT_LAT
  636. step_long = FLOAT_LONG
  637. parent = CellId.from_lat_lng(LatLng.from_degrees(FLOAT_LAT,
  638. FLOAT_LONG)).parent(15)
  639. h = get_heartbeat(args.auth_service, api_endpoint, access_token,
  640. profile_response)
  641. hs = [h]
  642. seen = set([])
  643.  
  644. for child in parent.children():
  645. latlng = LatLng.from_point(Cell(child).get_center())
  646. set_location_coords(latlng.lat().degrees, latlng.lng().degrees, 0)
  647. hs.append(
  648. get_heartbeat(args.auth_service, api_endpoint, access_token,
  649. profile_response))
  650. set_location_coords(step_lat, step_long, 0)
  651. visible = []
  652.  
  653. for hh in hs:
  654. try:
  655. for cell in hh.cells:
  656. for wild in cell.WildPokemon:
  657. hash = wild.SpawnPointId + ':' \
  658. + str(wild.pokemon.PokemonId)
  659. if hash not in seen:
  660. visible.append(wild)
  661. seen.add(hash)
  662. if cell.Fort:
  663. for Fort in cell.Fort:
  664. if Fort.Enabled == True:
  665. if args.china:
  666. (Fort.Latitude, Fort.Longitude) = \
  667. transform_from_wgs_to_gcj(Location(Fort.Latitude, Fort.Longitude))
  668. if Fort.GymPoints and args.display_gym:
  669. gyms[Fort.FortId] = [Fort.Team, Fort.Latitude,
  670. Fort.Longitude, Fort.GymPoints]
  671.  
  672. elif Fort.FortType \
  673. and args.display_pokestop:
  674. expire_time = 0
  675. if Fort.LureInfo.LureExpiresTimestampMs:
  676. expire_time = datetime\
  677. .fromtimestamp(Fort.LureInfo.LureExpiresTimestampMs / 1000.0)\
  678. .strftime("%H:%M:%S")
  679. if (expire_time != 0 or not args.onlylure):
  680. pokestops[Fort.FortId] = [Fort.Latitude,
  681. Fort.Longitude, expire_time]
  682. except AttributeError:
  683. break
  684.  
  685. for poke in visible:
  686. pokename = pokemonsJSON[str(poke.pokemon.PokemonId)]
  687. if args.ignore:
  688. if pokename.lower() in ignore:
  689. continue
  690. elif args.only:
  691. if pokename.lower() not in only:
  692. continue
  693.  
  694. disappear_timestamp = time.time() + poke.TimeTillHiddenMs \
  695. / 1000
  696.  
  697. if args.china:
  698. (poke.Latitude, poke.Longitude) = \
  699. transform_from_wgs_to_gcj(Location(poke.Latitude,
  700. poke.Longitude))
  701.  
  702. pokemons[poke.SpawnPointId] = {
  703. "lat": poke.Latitude,
  704. "lng": poke.Longitude,
  705. "disappear_time": disappear_timestamp,
  706. "id": poke.pokemon.PokemonId,
  707. "name": pokename
  708. }
  709.  
  710. def clear_stale_pokemons():
  711. current_time = time.time()
  712.  
  713. for pokemon_key in pokemons.keys():
  714. pokemon = pokemons[pokemon_key]
  715. if current_time > pokemon['disappear_time']:
  716. print "[+] removing stale pokemon %s at %f, %f from list" % (
  717. pokemon['name'].encode('utf-8'), pokemon['lat'], pokemon['lng'])
  718. del pokemons[pokemon_key]
  719.  
  720.  
  721. def register_background_thread(initial_registration=False):
  722. """
  723. Start a background thread to search for Pokemon
  724. while Flask is still able to serve requests for the map
  725. :param initial_registration: True if first registration and thread should start immediately, False if it's being called by the finishing thread to schedule a refresh
  726. :return: None
  727. """
  728.  
  729. debug('register_background_thread called')
  730. global search_thread
  731.  
  732. if initial_registration:
  733. if not werkzeug.serving.is_running_from_reloader():
  734. debug(
  735. 'register_background_thread: not running inside Flask so not starting thread')
  736. return
  737. if search_thread:
  738. debug(
  739. 'register_background_thread: initial registration requested but thread already running')
  740. return
  741.  
  742. debug('register_background_thread: initial registration')
  743. search_thread = threading.Thread(target=main)
  744.  
  745. else:
  746. debug('register_background_thread: queueing')
  747. search_thread = threading.Timer(30, main) # delay, in seconds
  748.  
  749. search_thread.daemon = True
  750. search_thread.name = 'search_thread'
  751. search_thread.start()
  752.  
  753.  
  754. def create_app():
  755. app = Flask(__name__, template_folder='templates')
  756.  
  757. GoogleMaps(app, key=GOOGLEMAPS_KEY)
  758. return app
  759.  
  760.  
  761. app = create_app()
  762.  
  763.  
  764. @app.route('/data')
  765. def data():
  766. """ Gets all the PokeMarkers via REST """
  767. return json.dumps(get_pokemarkers())
  768.  
  769. @app.route('/raw_data')
  770. def raw_data():
  771. """ Gets raw data for pokemons/gyms/pokestops via REST """
  772. return flask.jsonify(pokemons=pokemons, gyms=gyms, pokestops=pokestops)
  773.  
  774.  
  775. @app.route('/config')
  776. def config():
  777. """ Gets the settings for the Google Maps via REST"""
  778. center = {
  779. 'lat': FLOAT_LAT,
  780. 'lng': FLOAT_LONG,
  781. 'zoom': 15,
  782. 'identifier': "fullmap"
  783. }
  784. return json.dumps(center)
  785.  
  786.  
  787. @app.route('/')
  788. def fullmap():
  789. clear_stale_pokemons()
  790.  
  791. return render_template(
  792. 'example_fullmap.html', key=GOOGLEMAPS_KEY, fullmap=get_map(), auto_refresh=auto_refresh)
  793.  
  794.  
  795. @app.route('/next_loc')
  796. def next_loc():
  797. global NEXT_LAT, NEXT_LONG
  798.  
  799. lat = flask.request.args.get('lat', '')
  800. lon = flask.request.args.get('lon', '')
  801. if not (lat and lon):
  802. print('[-] Invalid next location: %s,%s' % (lat, lon))
  803. else:
  804. print('[+] Saved next location as %s,%s' % (lat, lon))
  805. NEXT_LAT = float(lat)
  806. NEXT_LONG = float(lon)
  807. return 'ok'
  808.  
  809.  
  810. def get_pokemarkers():
  811. pokeMarkers = [{
  812. 'icon': icons.dots.red,
  813. 'lat': origin_lat,
  814. 'lng': origin_lon,
  815. 'infobox': "Start position",
  816. 'type': 'custom',
  817. 'key': 'start-position',
  818. 'disappear_time': -1
  819. }]
  820.  
  821. for pokemon_key in pokemons:
  822. pokemon = pokemons[pokemon_key]
  823. datestr = datetime.fromtimestamp(pokemon[
  824. 'disappear_time'])
  825. dateoutput = datestr.strftime("%H:%M:%S")
  826. if is_ampm_clock:
  827. dateoutput = datestr.strftime("%I:%M%p").lstrip('0')
  828. pokemon['disappear_time_formatted'] = dateoutput
  829.  
  830. LABEL_TMPL = u'''
  831. <div><b>{name}</b><span> - </span><small><a href='http://www.pokemon.com/us/pokedex/{id}' target='_blank' title='View in Pokedex'>#{id}</a></small></div>
  832. <div>Disappears at - {disappear_time_formatted} <span class='label-countdown' disappears-at='{disappear_time}'></span></div>
  833. <div><a href='https://www.google.com/maps/dir/Current+Location/{lat},{lng}' target='_blank' title='View in Maps'>Get Directions</a></div>
  834. '''
  835. label = LABEL_TMPL.format(**pokemon)
  836. # NOTE: `infobox` field doesn't render multiple line string in frontend
  837. label = label.replace('\n', '')
  838.  
  839. pokeMarkers.append({
  840. 'type': 'pokemon',
  841. 'key': pokemon_key,
  842. 'disappear_time': pokemon['disappear_time'],
  843. 'icon': 'static/icons/%d.png' % pokemon["id"],
  844. 'lat': pokemon["lat"],
  845. 'lng': pokemon["lng"],
  846. 'infobox': label
  847. })
  848.  
  849. for gym_key in gyms:
  850. gym = gyms[gym_key]
  851. if gym[0] == 0:
  852. color = "rgba(0,0,0,.4)"
  853. if gym[0] == 1:
  854. color = "rgba(74, 138, 202, .6)"
  855. if gym[0] == 2:
  856. color = "rgba(240, 68, 58, .6)"
  857. if gym[0] == 3:
  858. color = "rgba(254, 217, 40, .6)"
  859.  
  860. icon = 'static/forts/'+numbertoteam[gym[0]]+'_large.png'
  861. pokeMarkers.append({
  862. 'icon': 'static/forts/' + numbertoteam[gym[0]] + '.png',
  863. 'type': 'gym',
  864. 'key': gym_key,
  865. 'disappear_time': -1,
  866. 'lat': gym[1],
  867. 'lng': gym[2],
  868. 'infobox': "<div><center><small>Gym owned by:</small><br><b style='color:" + color + "'>Team " + numbertoteam[gym[0]] + "</b><br><img id='" + numbertoteam[gym[0]] + "' height='100px' src='"+icon+"'><br>Prestige: " + str(gym[3]) + "</center>"
  869. })
  870. for stop_key in pokestops:
  871. stop = pokestops[stop_key]
  872. if stop[2] > 0:
  873. pokeMarkers.append({
  874. 'type': 'lured_stop',
  875. 'key': stop_key,
  876. 'disappear_time': -1,
  877. 'icon': 'static/forts/PstopLured.png',
  878. 'lat': stop[0],
  879. 'lng': stop[1],
  880. 'infobox': 'Lured Pokestop, expires at ' + stop[2],
  881. })
  882. else:
  883. pokeMarkers.append({
  884. 'type': 'stop',
  885. 'key': stop_key,
  886. 'disappear_time': -1,
  887. 'icon': 'static/forts/Pstop.png',
  888. 'lat': stop[0],
  889. 'lng': stop[1],
  890. 'infobox': 'Pokestop',
  891. })
  892. return pokeMarkers
  893.  
  894.  
  895. def get_map():
  896. fullmap = Map(
  897. identifier="fullmap2",
  898. style='height:100%;width:100%;top:0;left:0;position:absolute;z-index:200;',
  899. lat=origin_lat,
  900. lng=origin_lon,
  901. markers=get_pokemarkers(),
  902. zoom='15', )
  903. return fullmap
  904.  
  905.  
  906. if __name__ == '__main__':
  907. args = get_args()
  908. register_background_thread(initial_registration=True)
  909. app.run(debug=True, threaded=True, host=args.host, port=args.port)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement