freebies.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. import logging
  2. import re
  3. import time
  4. from datetime import date
  5. from pathlib import Path
  6. from bs4 import BeautifulSoup as bs
  7. class Freebies:
  8. def __init__(self, account):
  9. self.account = account
  10. # self.baseReferer = self.account.domain + '/'
  11. self.username = account.username
  12. self.pathString = '.debug'
  13. # Create debug directory
  14. self.debugOutput = Path(self.pathString)
  15. self.debugOutput.mkdir(exist_ok=True)
  16. # Links
  17. self.LINK_INDEX = '/index.html'
  18. def save(self, reply, name, JSON=False):
  19. timeNow = time.time_ns()
  20. today = date.today().isoformat()
  21. filename = '{}/{}-{}-{}-{}.{}'.format(
  22. self.pathString,
  23. self.username,
  24. today,
  25. name,
  26. timeNow,
  27. 'json' if JSON else 'html',
  28. )
  29. with open(filename, 'wb') as f:
  30. f.write(reply.content)
  31. def doTrudy(self):
  32. # Setup logger
  33. logger = logging.getLogger('neobots.Freebies.Trudy')
  34. # Constants
  35. LINK_TRUDY_1 = '/trudys_surprise.phtml'
  36. LINK_TRUDY_2 = '/trudydaily/slotgame.phtml'
  37. LINK_TRUDY_3 = '/trudydaily/js/slotsgame.js'
  38. LINK_TRUDY_4 = '/trudydaily/ajax/claimprize.php'
  39. PARAMS_TRUDY = {'delevent': 'yes'}
  40. DATA_TRUDY_1 = {'action': 'beginroll'}
  41. DATA_TRUDY_2 = {'action': 'prizeclaimed'}
  42. TEXT_TRUDY = "Trudy's Surprise"
  43. PATTERN_TRUDY_1 = re.compile(r'(?P<link>/trudydaily/slotgame\.phtml\?id=(?P<id>.*?)&slt=(?P<slt>\d+))')
  44. PATTERN_TRUDY_2 = re.compile(r'(?P<link>/trudydaily/js/slotsgame\.js\?v=(?P<v>\d+))')
  45. # Look for Trudy's Surprise event notfif at top of page
  46. result1 = self.account.get(self.LINK_INDEX)
  47. soup1 = bs(result1.content, 'lxml')
  48. soup1_match = soup1.select_one('#neobdy.en div#main div#header table tr td.eventIcon.sf b')
  49. # If event exists
  50. if soup1_match and (soup1_match.get_text() == TEXT_TRUDY):
  51. result2 = self.account.get(
  52. LINK_TRUDY_1,
  53. params=PARAMS_TRUDY,
  54. referer=self.LINK_INDEX
  55. )
  56. soup2 = bs(result2.content, 'lxml')
  57. soup2_match = soup2.select_one('#frameTest')
  58. # Check for trudy game link
  59. if soup2_match:
  60. soup2_regexmatch = PATTERN_TRUDY_1.search(soup2_match.get('src'))
  61. result3 = self.account.get(
  62. LINK_TRUDY_2,
  63. params={
  64. 'id': soup2_regexmatch['id'],
  65. 'slt': soup2_regexmatch['slt']
  66. },
  67. referer=LINK_TRUDY_1
  68. )
  69. soup3 = bs(result3.content, 'lxml')
  70. soup3_matches = soup3.select('script')
  71. # Select the second script element which has the link we need
  72. soup3_match = soup3_matches[1]
  73. # Check for slotsgame link
  74. if soup3_match:
  75. soup3_regexmatch = PATTERN_TRUDY_2.search(soup3_match.get('src'))
  76. result4 = self.account.get(
  77. LINK_TRUDY_3,
  78. params={'v': soup3_regexmatch['v']},
  79. referer=soup2_regexmatch['link']
  80. )
  81. # Start POSTing
  82. result5 = self.account.xhr(
  83. LINK_TRUDY_4,
  84. data={
  85. 'action': 'getslotstate',
  86. 'key': soup2_regexmatch['id']
  87. },
  88. referer=LINK_TRUDY_1
  89. )
  90. self.save(result5, 'trudy_getslotstate', JSON=True)
  91. json5 = result5.json()
  92. if not json5['error']:
  93. time.sleep(5)
  94. # Next POST
  95. result6 = self.account.xhr(
  96. LINK_TRUDY_4,
  97. data=DATA_TRUDY_1,
  98. referer=LINK_TRUDY_1
  99. )
  100. self.save(result6, 'trudy_beginroll', JSON=True)
  101. json6 = result6.json()
  102. if not json6['error']:
  103. # Prize has been won
  104. # Display before clicking the modal
  105. for prize in json6['prizes']:
  106. logger.info('Received: {} {}'.format(prize['value'], prize['name']))
  107. result7 = self.account.xhr(
  108. LINK_TRUDY_4,
  109. data=DATA_TRUDY_2,
  110. referer=LINK_TRUDY_1
  111. )
  112. json7 = result7.json()
  113. if not json7['error']:
  114. result8 = self.account.get(LINK_TRUDY_1, referer=LINK_TRUDY_1)
  115. else:
  116. logger.error(json7['error'])
  117. else:
  118. logger.error(json6['error'])
  119. else:
  120. logger.error(json5['error'])
  121. else:
  122. logger.error('No slotsgame.js link')
  123. else:
  124. logger.error('No slotgame link')
  125. else:
  126. logger.info("No Trudy's Surprise notification")
  127. def doSnowager(self):
  128. # Setup logger
  129. logger = logging.getLogger('neobots.Freebies.Snowager')
  130. # Constants
  131. LINK_SNOWAGER_1 = '/winter/snowager.phtml'
  132. LINK_SNOWAGER_2 = '/winter/snowager2.phtml'
  133. TEXT_SNOWAGER = 'Attempt to steal a piece of treasure'
  134. PATTERN_SNOWAGER_1 = re.compile(r'You carefully walk in and pick up a')
  135. PATTERN_SNOWAGER_2 = re.compile(r'You carefully walk in and hastily pick up an item')
  136. PATTERN_SNOWAGER_3 = re.compile(r'You have already collected your prize today.')
  137. PATTERN_SNOWAGER_4 = re.compile(r'Come back later.')
  138. PATTERN_SNOWAGER_5 = re.compile(r'The Snowager is awake')
  139. PATTERN_SNOWAGER_6 = re.compile(r'The Snowager moves slightly in its sleep')
  140. PATTERN_SNOWAGER_7 = re.compile(r'The Snowager awakes, looks straight at you')
  141. PATTERN_SNOWAGER_8 = re.compile(r'ROOOOAARRR')
  142. # Visit snowager page
  143. result1 = self.account.get(LINK_SNOWAGER_1)
  144. soup1 = bs(result1.content, 'lxml')
  145. soup1_match = soup1.select_one('.content center form input')
  146. # Probe snowager
  147. if soup1_match and soup1_match.get('value') == TEXT_SNOWAGER:
  148. result2 = self.account.get(LINK_SNOWAGER_2, referer=LINK_SNOWAGER_1)
  149. self.save(result2, 'snowager')
  150. soup2 = bs(result2.content, 'lxml')
  151. soup2_match_1 = soup2.select_one('td.content center p')
  152. soup2_match_1_text = soup2_match_1.get_text()
  153. if PATTERN_SNOWAGER_1.search(soup2_match_1_text):
  154. soup2_match_2 = soup2.select_one('td.content center p b')
  155. if soup2_match_2:
  156. logger.info('Received: {}'.format(soup2_match_2.get_text()))
  157. elif PATTERN_SNOWAGER_2.search(soup2_match_1_text):
  158. soup2_match_2 = soup2.select_one('td.content center p b')
  159. if soup2_match_2:
  160. logger.info('Received an exclusive prize: {}'.format(soup2_match_2.get_text()))
  161. elif PATTERN_SNOWAGER_3.search(soup2_match_1_text):
  162. logger.info('[Advent] The Snowager has been visited today')
  163. elif PATTERN_SNOWAGER_4.search(soup2_match_1_text):
  164. logger.info('The Snowager has been visited already')
  165. elif PATTERN_SNOWAGER_5.search(soup2_match_1_text):
  166. logger.info('The Snowager is awake!')
  167. elif PATTERN_SNOWAGER_6.search(soup2_match_1_text) or PATTERN_SNOWAGER_7.search(soup2_match_1_text):
  168. logger.info('Received nothing')
  169. elif PATTERN_SNOWAGER_8.search(soup2_match_1_text):
  170. logger.info('The Snowager attacked!')
  171. else:
  172. logger.warning('Unknown event!')
  173. else:
  174. logger.info('The Snowager is awake')
  175. def doAnchor(self):
  176. # Setup logger
  177. logger = logging.getLogger('neobots.Freebies.Anchor')
  178. # Constants
  179. LINK_ANCHOR = '/pirates/anchormanagement.phtml'
  180. # Visit page
  181. result1 = self.account.get(LINK_ANCHOR)
  182. soup1 = bs(result1.content, 'lxml')
  183. soup1_match = soup1.select_one('#form-fire-cannon input')
  184. # Grab form value and POST
  185. if soup1_match:
  186. soup1_value = soup1_match.get('value')
  187. result2 = self.account.post(
  188. LINK_ANCHOR,
  189. data={'action': soup1_value},
  190. referer=LINK_ANCHOR
  191. )
  192. self.save(result2, 'anchormanagement')
  193. # Find prize
  194. soup2 = bs(result2.content, 'lxml')
  195. soup2_match = soup2.select_one('.prize-item-name')
  196. if soup2_match:
  197. soup2_name = soup2_match.get_text()
  198. logger.info('Received: {}'.format(soup2_name))
  199. else:
  200. logger.info('Received nothing')
  201. else:
  202. logger.info('Already visited today!')
  203. def doAppleBobbing(self):
  204. # Setup logger
  205. logger = logging.getLogger('neobots.Freebies.AppleBobbing')
  206. # Constants
  207. LINK_APPLEBOB = '/halloween/applebobbing.phtml'
  208. PARAMS_APPLEBOB = {'bobbing': '1'}
  209. PATTERN_APPLEBOB_1 = re.compile(r'As you gaze into the water, about to bob your head in for a chance at appley-goodness')
  210. # Visit page
  211. result1 = self.account.get(LINK_APPLEBOB)
  212. soup1 = bs(result1.content, 'lxml')
  213. soup1_match = soup1.select_one('#bob_content a')
  214. # Bob for apples
  215. if soup1_match:
  216. result2 = self.account.get(
  217. LINK_APPLEBOB,
  218. params=PARAMS_APPLEBOB,
  219. referer=LINK_APPLEBOB
  220. )
  221. self.save(result2, 'applebobbing')
  222. # Find prize
  223. soup2 = bs(result2.content, 'lxml')
  224. soup2_match1 = soup2.select_one('#bob_middle center b')
  225. soup2_match2 = soup2.select_one('#bob_middle')
  226. if soup2_match1:
  227. logger.info('Received: {}'.format(soup2_match1.get_text()))
  228. else:
  229. logger.info('Received nothing!')
  230. else:
  231. logger.info('Already visited today!')
  232. def doAdvent(self):
  233. # Setup logger
  234. logger = logging.getLogger('neobots.Freebies.Advent')
  235. # Constants
  236. LINK_ADVENT_1 = '/winter/adventcalendar.phtml'
  237. LINK_ADVENT_2 = '/winter/adventClick.php'
  238. LINK_ADVENT_3 = '/winter/process_adventcalendar.phtml'
  239. TEXT_ADVENT = 'Collect My Prize!!!'
  240. PATTERN_ADVENT_1 = re.compile(r'day: "(?P<day>\d+?)"')
  241. PATTERN_ADVENT_2 = re.compile(r'ck: "(?P<ck>.+?)"')
  242. # Visit page
  243. result1 = self.account.get(LINK_ADVENT_1)
  244. soup1 = bs(result1.content, 'lxml')
  245. soup1_match = soup1.select_one('.content div form input')
  246. # Check for receive rewards button!
  247. if soup1_match and soup1_match.get('value') == TEXT_ADVENT:
  248. match1 = PATTERN_ADVENT_1.search(result1.text)
  249. match2 = PATTERN_ADVENT_2.search(result1.text)
  250. # Click hidden object
  251. if match1 and match2:
  252. result2 = self.account.post(
  253. LINK_ADVENT_2,
  254. data={
  255. 'day': match1['day'],
  256. 'ck': match2['ck']
  257. },
  258. referer=LINK_ADVENT_1
  259. )
  260. self.save(result2, 'adventHidden')
  261. logger.info('Received: {}'.format(result2.json()['prize']['name']))
  262. # Get rewards
  263. result3 = self.account.post(
  264. LINK_ADVENT_3,
  265. referer=LINK_ADVENT_1
  266. )
  267. self.save(result3, 'adventRegular')
  268. soup3 = bs(result3.content, 'lxml')
  269. soup3_matches = soup3.select('.content div center b')
  270. if soup3_matches:
  271. for match in soup3_matches:
  272. logger.info('Received {}'.format(match.get_text()))
  273. else:
  274. logger.info('Received nothing!')
  275. else:
  276. logger.info('Already visited today!')
  277. def doBankCollect(self):
  278. # Setup logger
  279. logger = logging.getLogger('neobots.Freebies.BankCollect')
  280. # Constants
  281. LINK_BANK_1 = '/bank.phtml'
  282. LINK_BANK_2 = '/process_bank.phtml'
  283. DATA_BANK = {'type': 'interest'}
  284. PATTERN_BANK = re.compile(r'Collect Interest \((?P<np>\d+) NP\)')
  285. # Visit page
  286. result1 = self.account.get(LINK_BANK_1)
  287. soup = bs(result1.content, 'lxml')
  288. soup_matches = soup.select('.contentModuleContent div form input')
  289. if soup_matches:
  290. soup_match = soup_matches[-1] # Last match since there are other form inputs
  291. match = PATTERN_BANK.search(soup_match.get('value'))
  292. # Collect interest
  293. if match:
  294. result2 = self.account.post(
  295. LINK_BANK_2,
  296. data=DATA_BANK,
  297. referer=LINK_BANK_1
  298. )
  299. self.save(result2, 'bankCollect')
  300. logger.info('Collected: {} NP'.format(match['np']))
  301. else:
  302. logger.warning('No collect button!')
  303. else:
  304. logger.info('Already collected or transacted today!')
  305. # TODO: Add auto bank account upgrade
  306. def doColtzan(self):
  307. # Setup logger
  308. logger = logging.getLogger('neobots.Freebies.Coltzan')
  309. # Constants
  310. LINK_COLTZAN = '/desert/shrine.phtml'
  311. DATA_COLTZAN = {'type': 'approach'}
  312. TEXT_COLTZAN = 'Approach the Shrine'
  313. # Visit page
  314. result1 = self.account.get(LINK_COLTZAN)
  315. soup1 = bs(result1.content, 'lxml')
  316. soup1_matches = soup1.select('.content div form input')
  317. soup1_match = soup1_matches[1] # First match is hidden input
  318. # Approach the shrine + also works for nothing happens
  319. if soup1_match and soup1_match.get('value') == TEXT_COLTZAN:
  320. result2 = self.account.post(
  321. LINK_COLTZAN,
  322. data=DATA_COLTZAN,
  323. referer=LINK_COLTZAN
  324. )
  325. self.save(result2, 'coltzan')
  326. soup2 = bs(result2.content, 'lxml')
  327. soup2_match = soup2.select_one('.content div div p')
  328. logger.info(soup2_match.get_text())
  329. else:
  330. logger.info('Already visited today!')
  331. def doDailyPuzzle(self):
  332. # Setup logger
  333. logger = logging.getLogger('neobots.Freebies.DailyPuzzle')
  334. # Constants
  335. LINK_PUZZLE_1 = '/community/index.phtml'
  336. LINK_PUZZLE_2 = 'http://www.jellyneo.net/?go=dailypuzzle'
  337. # Visit page
  338. result1 = self.account.get(LINK_PUZZLE_1)
  339. soup1 = bs(result1.content, 'lxml')
  340. # Question
  341. soup1_match1 = soup1.select_one('.question')
  342. # Date
  343. soup1_match2 = soup1.select_one('form[action="/community/index.phtml"] input')
  344. date = soup1_match2.get('value')
  345. # Visit Jellyneo solutions page
  346. result2 = self.account.get(LINK_PUZZLE_2)
  347. soup2 = bs(result2.content, 'lxml')
  348. soup2_matches = soup2.select('.panel p')
  349. # Uuestion
  350. soup2_match1 = soup2_matches[2]
  351. # Answer
  352. soup2_match2 = soup2_matches[3]
  353. # Check if question matches
  354. if soup1_match1.get_text() in soup2_match1.get_text():
  355. # Get options
  356. soup1_matches = soup1.select('select[name="trivia_response"] option')
  357. trivia_value = None
  358. for match in soup1_matches:
  359. if match.get_text() in soup2_match2.get_text():
  360. trivia_value = match.get('value')
  361. if trivia_value:
  362. result3 = self.account.post(
  363. LINK_PUZZLE_1,
  364. data={
  365. 'trivia_date': date,
  366. 'trivia_response': trivia_value,
  367. 'submit': 'Submit'
  368. },
  369. referer=LINK_PUZZLE_1
  370. )
  371. self.save(result3, 'dailyPuzzle')
  372. soup3 = bs(result3.content, 'lxml')
  373. soup3_matches = soup3.select('.question b')
  374. # If NP and item
  375. if len(soup3_matches) > 1:
  376. logger.info('Received: {} NP'.format(soup3_matches[0].get_text()))
  377. logger.info('Received: {}'.format(soup3_matches[1].get_text()))
  378. # Else if only NP
  379. else:
  380. logger.info('Received: {}'.format(soup3_matches[0].get_text()))
  381. else:
  382. logger.error('Matching trivia answer not found!')
  383. else:
  384. logger.error('Matching trivia question not found!')
  385. def doQuarry(self):
  386. # Setup logger
  387. logger = logging.getLogger('neobots.Freebies.Quarry')
  388. # Constants
  389. LINK_QUARRY = '/magma/quarry.phtml'
  390. TEXT_QUARRY = "Hey! What do you think you're doing?!"
  391. # Visit page
  392. result = self.account.get(LINK_QUARRY)
  393. self.save(result, 'quarry')
  394. soup = bs(result.content, 'lxml')
  395. soup_match = soup.select_one('.content div b')
  396. if soup_match and not soup_match.get_text() == TEXT_QUARRY:
  397. logger.info('Received: {}'.format(soup_match.get_text()))
  398. else:
  399. logger.info('Already visited today!')