1.diff (45682B)
1 diff --git a/README.md b/README.md 2 index 0d3c137..5dcbdb8 100644 3 --- a/README.md 4 +++ b/README.md 5 @@ -11,18 +11,23 @@ Get and post a screenshot of the Intel Map. 6 ## Install 7 To install the plugin you need to: 8 9 -1. Clone this repo into `<yourBotDir>/plugins/` 10 -2. Optional remove `README.md` `LICENSE` and `.gitignore` 11 -3. Follow Configuration. 12 +1. Go into `<yourBotDir>/plugins/` 13 +2. Clone this repo into `intel_screenbot` 14 +3. Optional remove `README.md` `LICENSE` and `.gitignore` from `<yourBotDir>/plugins/intel_screenbot` 15 +4. Run `pip3 install -r requirements.txt` 16 +5. Follow Configuration. 17 18 ## Configuration 19 For using the Intel Screenbot you need to add the following to the config.json: 20 21 ``` 22 "intel_screenbot": { 23 - "SACSID": "YOUR SACSID", 24 - "CSRF": "YOUR CSRF" 25 - } 26 + "SACSID": "YOUR SACSID", 27 + "CSRF": "YOUR CSRF", 28 + "plugin_dirs": [ 29 + "http://iitc.jonatkins.com/release/plugins" 30 + ] 31 + } 32 ``` 33 34 According to the official INSTALL Documention of the hangoutbot you will find the config.json in `/<username>/.local/share/hangupsbot/` 35 @@ -30,6 +35,25 @@ According to the official INSTALL Documention of the hangoutbot you will find th 36 37 Also you need to add `intel_screenbot` to the plugins. 38 39 +## How to add gitlab to plugin_dirs 40 + 41 +1. Open in browser: `https://gitlab.com/api/v3/projects/search/:REPO_NAME` 42 +2. copy the number in `id` 43 +3. add `http://gitlab.com/api/v3/projects/:ID/repository/tree` to `plugin_dirs` 44 +4. add `"gitlab_token":"YOUR_GITLAB_API_TOKEN"` to `intel_screenbot` 45 + 46 +*Note: repos are currently locked to master branch* 47 + 48 +## How to add github to plugins_dir 49 + 50 +1. add `https://api.github.com/repos/:REPO_USER/:REPO_NAME/git/trees/master?recursive=1` 51 + 52 +## How to add local files to plugins_dir 53 + 54 +1. just add the absolute path to `plugins_dir` (relative paths are not tested) 55 + 56 +*Note: repos are currently locked to master branch* 57 + 58 ## How to get SACSID and CSRF 59 You should look at the Documentation of [ingress-ice](https://github.com/nibogd/ingress-ice/wiki/Cookies-Authentication) 60 61 @@ -41,13 +65,29 @@ You should look at the Documentation of [ingress-ice](https://github.com/nibogd/ 62 `/bot clearintel` 63 * Clears the default screenshot URL of a particular hangout. 64 65 +`/bot show_iitcplugins` 66 +* Shows every availible IITC-plugin. 67 + 68 +`/bot set_iitcplugins <plugin names devided by whitespace>` 69 +* Sets the plugins to use with IITC per hangout. 70 + 71 +`/bot clear_iitcplugins` 72 +* Clear the plugins to use with IITC per hangout. 73 + 74 + 75 ## User Command 76 77 -`/bot intel [<url>]` 78 +`/bot intel [<url> or <searchTerm>]` 79 * Provide an arbitrary `<url>` to take a screenshot 80 * If no `<url>` is supplied, use the default screenshot URL (or reply with an error if no URL is set) 81 82 -## PhantomJS Installation 83 +`/bot iitc [<url> or <searchTerm>]` 84 +* Provide an arbitrary `<url>` to take a screenshot 85 +* If no `<url>` is supplied, use the default screenshot URL (or reply with an error if no URL is set) 86 + 87 +## PhantomJS Installation 88 + 89 +*May be outdated* 90 91 ### Debian-based distros (e.g. Ubuntu 14.04) 92 93 diff --git a/__init__.py b/__init__.py 94 new file mode 100644 95 index 0000000..2648a61 96 --- /dev/null 97 +++ b/__init__.py 98 @@ -0,0 +1,315 @@ 99 +from bs4 import BeautifulSoup 100 +import requests 101 +import json 102 +import asyncio, io, logging, os, re, time, tempfile 103 +import subprocess 104 +import plugins 105 +import re 106 +from asyncio import subprocess 107 +from shutil import move 108 +from os import remove, close 109 + 110 +logger = logging.getLogger(__name__) 111 + 112 + 113 +def _initialise(bot): 114 + plugins.register_user_command(["intel", "iitc"]) 115 + plugins.register_admin_command(["setintel", "clearintel", "show_iitcplugins", "set_iitcplugins", "clear_iitcplugins"]) 116 + _get_iitc_plugins(bot) 117 + 118 + 119 +@asyncio.coroutine 120 +def _open_file(name): 121 + logger.debug("opening screenshot file: {}".format(name)) 122 + return open(name, 'rb') 123 + 124 +def _parse_onlineRepos(url, ext=''): 125 + logger.debug("parsing github or gitlab or http(s)") 126 + page = requests.get(url).text 127 + if 'gitlab.com' in url: 128 + files = [] 129 + for json_page in json.loads(page): 130 + for attribute, value in json_page.items(): 131 + if attribute == "name": 132 + if value.endswith(ext): 133 + files.append(url.replace("/tree/", "/blobs/master") + "&filepath=" + value) 134 + return files 135 + elif 'github.com' in url: 136 + files = [] 137 + for attribute, value in json.loads(page).items(): 138 + if attribute == "tree": 139 + for tree in value: 140 + for attribute, value in tree.items(): 141 + if attribute == "path": 142 + if value.endswith(ext): 143 + files.append(url.replace("https://api.github.com/repos/", "https://raw.githubusercontent.com/").replace("git/trees/",'').replace("master?recursive=1","master/") + value) 144 + return files 145 + else: 146 + soup = BeautifulSoup(page, 'html.parser') 147 + return [url + '/' + node.get('href') for node in soup.find_all('a') if node.get('href').endswith(ext)] 148 + 149 +def _get_iitc_plugins(bot): 150 + logger.debug("getting availible plugins") 151 + if bot.config.exists(["intel_screenbot", "gitlab_token"]): 152 + token = bot.config.get_by_path(["intel_screenbot", "gitlab_token"]) 153 + url_config = bot.config.get_by_path(["intel_screenbot", "plugin_dirs"]) 154 + ext = '.user.js' 155 + data=[] 156 + for url in url_config: 157 + if ext in url: 158 + item = {"name": url.split('/', url.count('/'))[-1].replace(ext, ''), "url": url} 159 + data.append(item) 160 + else: 161 + if "gitlab.com" in url: 162 + url = url + '?private_token=' + token 163 + for file in _parse_onlineRepos(url, ext): 164 + if "gitlab.com" in url: 165 + item = {"name": file.split('=', file.count('='))[-1].replace(ext, ''), "url": file} 166 + elif 'github.com' in url: 167 + item = {"name": file.split('/', file.count('/'))[-1].replace(ext, ''), "url": file} 168 + else: 169 + item = {"name": file.split('/', file.count('/'))[-1].replace(ext, ''), "url": file} 170 + data.append(item) 171 + 172 + iitc_plugins = data 173 + if bot.memory.exists(["iitc_plugins"]): 174 + bot.memory.pop_by_path(["iitc_plugins"]) 175 + bot.memory.set_by_path(["iitc_plugins"], iitc_plugins) 176 + else: 177 + bot.memory.set_by_path(["iitc_plugins"], iitc_plugins) 178 + 179 +@asyncio.coroutine 180 +def _get_lines(shell_command): 181 + p = yield from asyncio.create_subprocess_shell(shell_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 182 + stdout, stderr = yield from p.communicate() 183 + return p.returncode, stdout 184 + 185 +@asyncio.coroutine 186 +def _screencap(maptype, url, filepath, filename, SACSID, CSRF, plugins, search, bot, event): 187 + loop = asyncio.get_event_loop() 188 + logger.info("screencapping {} and saving as {}".format(url, filepath)) 189 + if plugins is '': 190 + if search == False: 191 + command = 'phantomjs hangupsbot/plugins/intel_screenbot/screencap_' + maptype + '.js "' + SACSID + '" "' + CSRF + '" "' + url + '" "' + filepath + '"' 192 + task = _get_lines(command) 193 + task = asyncio.wait_for(task, 180.0, loop=self.loop) 194 + exitcode, stdout = loop.run_until_complete(task) 195 + else: 196 + command = 'phantomjs hangupsbot/plugins/intel_screenbot/screencap_' + maptype + '.js "' + SACSID + '" "' + CSRF + '" "' + url + '" "' + filepath + '" "' + search + '"' 197 + task = _get_lines(command) 198 + task = asyncio.wait_for(task, 180.0, loop=loop) 199 + exitcode, stdout = yield from task 200 + else: 201 + if search == False: 202 + command = 'phantomjs hangupsbot/plugins/intel_screenbot/screencap_' + maptype + '.js "' + SACSID + '" "' + CSRF + '" "' + url + '" "' + filepath + '" "' + plugins + '"' 203 + task = _get_lines(command) 204 + task = asyncio.wait_for(task, 180.0, loop=self.loop) 205 + exitcode, stdout = loop.run_until_complete(task) 206 + else: 207 + command = 'phantomjs hangupsbot/plugins/intel_screenbot/screencap_' + maptype + '.js "' + SACSID + '" "' + CSRF + '" "' + url + '" "' + filepath + '" "' + search + '" "' + plugins + '"' 208 + task = _get_lines(command) 209 + task = asyncio.wait_for(task, 180.0, loop=loop) 210 + exitcode, stdout = yield from task 211 + 212 + # read the resulting file into a byte array 213 + file_resource = yield from _open_file(filepath) 214 + file_data = yield from loop.run_in_executor(None, file_resource.read) 215 + image_data = yield from loop.run_in_executor(None, io.BytesIO, file_data) 216 + try: 217 + image_id = yield from bot._client.upload_image(image_data, filename=filename) 218 + yield from bot._client.sendchatmessage(event.conv.id_, None, image_id=image_id) 219 + except Exception as e: 220 + yield from bot.coro_send_message(event.conv_id, "<i>error uploading screenshot</i>") 221 + logger.exception("upload failed".format(url)) 222 + 223 + 224 +def setintel(bot, event, *args): 225 + """set url for current converation for the intel or iitc command. 226 + use /bot clearintel to clear the previous url before setting a new one. 227 + """ 228 + url = bot.conversation_memory_get(event.conv_id, 'IntelURL') 229 + if url is None: 230 + bot.conversation_memory_set(event.conv_id, 'IntelURL', ''.join(args)) 231 + html = "<i><b>{}</b> updated screenshot URL".format(event.user.full_name) 232 + yield from bot.coro_send_message(event.conv, html) 233 + 234 + else: 235 + html = "<i><b>{}</b> URL already exists for this conversation!<br /><br />".format(event.user.full_name) 236 + html += "<i>Clear it first with /bot clearintel before setting a new one." 237 + yield from bot.coro_send_message(event.conv, html) 238 + 239 + 240 +def clearintel(bot, event, *args): 241 + """clear url for current converation for the intel or iitc command. 242 + """ 243 + url = bot.conversation_memory_get(event.conv_id, 'IntelURL') 244 + if url is None: 245 + html = "<i><b>{}</b> nothing to clear for this conversation".format(event.user.full_name) 246 + yield from bot.coro_send_message(event.conv, html) 247 + 248 + else: 249 + bot.conversation_memory_set(event.conv_id, 'IntelURL', None) 250 + html = "<i><b>{}</b> URL cleared for this conversation!<br />".format(event.user.full_name) 251 + yield from bot.coro_send_message(event.conv, html) 252 + 253 + 254 +def intel(bot, event, *args): 255 + """get a screenshot of a search term or intel URL or the default intel URL of the hangout. 256 + """ 257 + 258 + if args: 259 + if len(args) > 1: 260 + url = ' '.join(str(i) for i in args) 261 + else: 262 + url = args[0] 263 + if '"' in url: 264 + url = url.replace('"', '') 265 + else: 266 + url = bot.conversation_memory_get(event.conv_id, 'IntelURL') 267 + 268 + if bot.config.exists(["intel_screenbot", "SACSID"]): 269 + SACSID = bot.config.get_by_path(["intel_screenbot", "SACSID"]) 270 + else: 271 + html = "<i><b>{}</b> No Intel SACSID Cookie has been added to config. Unable to authenticate".format(event.user.full_name) 272 + yield from bot.coro_send_message(event.conv, html) 273 + if bot.config.exists(["intel_screenbot", "CSRF"]): 274 + CSRF = bot.config.get_by_path(["intel_screenbot", "CSRF"]) 275 + else: 276 + html = "<i><b>{}</b> No Intel CSRF Cookie has been added to config. Unable to authenticate".format(event.user.full_name) 277 + yield from bot.coro_send_message(event.conv, html) 278 + 279 + if url is None: 280 + html = "<i><b>{}</b> No Intel URL or search term has been set for screenshots.".format(event.user.full_name) 281 + yield from bot.coro_send_message(event.conv, html) 282 + 283 + else: 284 + if re.match(r'^[a-zA-Z]+://', url): 285 + search = False 286 + ZoomSearch = re.finditer(r"(?:&z=).*", url) 287 + for matchNum, zoomlevel_raw in enumerate(ZoomSearch): 288 + matchNum = matchNum + 1 289 + zoomlevel_clean = zoomlevel_raw.group() 290 + zoomlevel = zoomlevel_clean[3:][:2] 291 + if zoomlevel.isdigit(): 292 + yield from bot.coro_send_message(event.conv_id, "<i>intel map at zoom level "+ zoomlevel + " requested, please wait...</i>") 293 + else: 294 + yield from bot.coro_send_message(event.conv_id, "<i>intel map at last zoom level requested, please wait...</i>") 295 + else: 296 + search = url 297 + logger.info(search); 298 + url = 'https://www.ingress.com/intel' 299 + yield from bot.coro_send_message(event.conv_id, "<i>intel map is searching " + search + " and screenshooting as requested, please wait...</i>") 300 + 301 + filename = event.conv_id + "." + str(time.time()) +".png" 302 + filepath = tempfile.NamedTemporaryFile(prefix=event.conv_id, suffix=".png", delete=False).name 303 + logger.debug("temporary screenshot file: {}".format(filepath)) 304 + try: 305 + loop = asyncio.get_event_loop() 306 + image_data = yield from _screencap("intel", url, filepath, filename, SACSID, CSRF, "", search, bot, event) 307 + except Exception as e: 308 + yield from bot.coro_send_message(event.conv_id, "<i>error getting screenshot</i>") 309 + logger.exception("screencap failed".format(url)) 310 + return 311 + 312 + 313 +def iitc(bot, event, *args): 314 + """get a screenshot of a search term or intel URL or the default intel URL of the hangout. 315 + """ 316 + 317 + if args: 318 + if len(args) > 1: 319 + url = ' '.join(str(i) for i in args) 320 + else: 321 + url = args[0] 322 + if '"' in url: 323 + url = url.replace('"', '') 324 + else: 325 + url = bot.conversation_memory_get(event.conv_id, 'IntelURL') 326 + 327 + if bot.config.exists(["intel_screenbot", "SACSID"]): 328 + SACSID = bot.config.get_by_path(["intel_screenbot", "SACSID"]) 329 + else: 330 + html = "<i><b>{}</b> No Intel SACSID Cookie has been added to config. Unable to authenticate".format(event.user.full_name) 331 + yield from bot.coro_send_message(event.conv, html) 332 + if bot.config.exists(["intel_screenbot", "CSRF"]): 333 + CSRF = bot.config.get_by_path(["intel_screenbot", "CSRF"]) 334 + else: 335 + html = "<i><b>{}</b> No Intel CSRF Cookie has been added to config. Unable to authenticate".format(event.user.full_name) 336 + yield from bot.coro_send_message(event.conv, html) 337 + 338 + if url is None: 339 + html = "<i><b>{}</b> No Intel URL has been set for screenshots.".format(event.user.full_name) 340 + yield from bot.coro_send_message(event.conv, html) 341 + 342 + else: 343 + if re.match(r'^[a-zA-Z]+://', url): 344 + search = False 345 + ZoomSearch = re.finditer(r"(?:&z=).*", url) 346 + for matchNum, zoomlevel_raw in enumerate(ZoomSearch): 347 + matchNum = matchNum + 1 348 + zoomlevel_clean = zoomlevel_raw.group() 349 + zoomlevel = zoomlevel_clean[3:][:2] 350 + if zoomlevel.isdigit(): 351 + yield from bot.coro_send_message(event.conv_id, "<i>intel map at zoom level "+ zoomlevel + " requested, please wait...</i>") 352 + else: 353 + yield from bot.coro_send_message(event.conv_id, "<i>intel map at last zoom level requested, please wait...</i>") 354 + else: 355 + search = url 356 + logger.info(search); 357 + url = 'https://www.ingress.com/intel' 358 + yield from bot.coro_send_message(event.conv_id, "<i>intel map is searching " + search + " and screenshooting as requested, please wait...</i>") 359 + 360 + filename = event.conv_id + "." + str(time.time()) +".png" 361 + filepath = tempfile.NamedTemporaryFile(prefix=event.conv_id, suffix=".png", delete=False).name 362 + plugins_filepath = tempfile.NamedTemporaryFile(prefix=event.conv_id, suffix=".json", delete=False).name 363 + logger.debug("temporary screenshot file: {}".format(filepath)) 364 + if bot.conversation_memory_get(event.conv_id, 'iitc_plugins'): 365 + plugins = [] 366 + plugin_names = bot.conversation_memory_get(event.conv_id, 'iitc_plugins').split(", ") 367 + if bot.memory.exists(["iitc_plugins"]): 368 + for plugin_objects in bot.memory.get_by_path(["iitc_plugins"]): 369 + for plugin_name in plugin_names: 370 + if plugin_objects["name"] == plugin_name: 371 + plugins.append(plugin_objects["url"]) 372 + else: 373 + plugins = '' 374 + 375 + with open(plugins_filepath, 'w') as out: 376 + out.write(json.dumps(plugins)) 377 + 378 + try: 379 + loop = asyncio.get_event_loop() 380 + image_data = yield from _screencap("iitc", url, filepath, filename, SACSID, CSRF, plugins_filepath, search, bot, event) 381 + except Exception as e: 382 + yield from bot.coro_send_message(event.conv_id, "<i>error getting screenshot</i>") 383 + logger.exception("screencap failed".format(url)) 384 + return 385 + 386 +def show_iitcplugins(bot, event, *args): 387 + if bot.memory.exists(["iitc_plugins"]): 388 + plugin_names = [] 389 + for plugin_objects in bot.memory.get_by_path(["iitc_plugins"]): 390 + for attribute, value in plugin_objects.items(): 391 + if attribute == "name": 392 + plugin_names.append(value) 393 + yield from bot.coro_send_to_user_and_conversation(event.user.id_.chat_id, event.conv_id, "<i><b>IITC Plugins:</b><br> {}</i>".format(', <br>'.join(str(i) for i in plugin_names)), _("<i><b>{}</b>, I've sent you the plugins ;)</i>").format(event.user.full_name)) 394 + 395 +def set_iitcplugins(bot, event, *args): 396 + if not bot.conversation_memory_get(event.conv_id, 'iitc_plugins') is None: 397 + html = "<i><b>{}</b> plugins already set for this conversation!<br /><br />".format(event.user.full_name) 398 + html += "<i>Clear them first with /bot clear_iitcplugins before setting new ones." 399 + yield from bot.coro_send_message(event.conv, html) 400 + else: 401 + bot.conversation_memory_set(event.conv_id, 'iitc_plugins', ', '.join(args)) 402 + html = "<i><b>{}</b> updated plugins".format(event.user.full_name) 403 + yield from bot.coro_send_message(event.conv, html) 404 + 405 +def clear_iitcplugins(bot, event, *args): 406 + if bot.conversation_memory_get(event.conv_id, 'iitc_plugins') is None: 407 + html = "<i><b>{}</b> nothing to clear for this conversation".format(event.user.full_name) 408 + yield from bot.coro_send_message(event.conv, html) 409 + 410 + else: 411 + bot.conversation_memory_set(event.conv_id, 'iitc_plugins', None) 412 + html = "<i><b>{}</b> plugins cleared for this conversation!<br />".format(event.user.full_name) 413 + yield from bot.coro_send_message(event.conv, html) 414 diff --git a/intel_screenbot/__init__.py b/intel_screenbot/__init__.py 415 deleted file mode 100644 416 index 880436e..0000000 417 --- a/intel_screenbot/__init__.py 418 +++ /dev/null 419 @@ -1,136 +0,0 @@ 420 -import asyncio, io, logging, os, re, time, tempfile 421 -import subprocess 422 -import plugins 423 -import re 424 -from asyncio import subprocess 425 - 426 -logger = logging.getLogger(__name__) 427 - 428 - 429 -def _initialise(bot): 430 - plugins.register_user_command(["intel"]) 431 - plugins.register_admin_command(["setintel", "clearintel"]) 432 - 433 -@asyncio.coroutine 434 -def _open_file(name): 435 - logger.debug("opening screenshot file: {}".format(name)) 436 - return open(name, 'rb') 437 - 438 -@asyncio.coroutine 439 -def _get_lines(shell_command): 440 - p = yield from asyncio.create_subprocess_shell(shell_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 441 - stdout, stderr = yield from p.communicate() 442 - return p.returncode, stdout 443 - 444 -@asyncio.coroutine 445 -def _screencap(url, filepath, filename, SACSID, CSRF, search, bot, event): 446 - loop = asyncio.get_event_loop() 447 - logger.info("screencapping {} and saving as {}".format(url, filepath)) 448 - if search == False: 449 - command = 'phantomjs hangupsbot/plugins/intel_screenbot/screencap.js "' + SACSID + '" "' + CSRF + '" "' + url + '" "' + filepath + '"' 450 - task = _get_lines(command) 451 - task = asyncio.wait_for(task, 180.0, loop=self.loop) 452 - exitcode, stdout = loop.run_until_complete(task) 453 - else: 454 - command = 'phantomjs hangupsbot/plugins/intel_screenbot/screencap.js "' + SACSID + '" "' + CSRF + '" "' + url + '" "' + filepath + '" "' + search + '"' 455 - task = _get_lines(command) 456 - task = asyncio.wait_for(task, 180.0, loop=loop) 457 - exitcode, stdout = yield from task 458 - 459 - # read the resulting file into a byte array 460 - file_resource = yield from _open_file(filepath) 461 - file_data = yield from loop.run_in_executor(None, file_resource.read) 462 - image_data = yield from loop.run_in_executor(None, io.BytesIO, file_data) 463 - try: 464 - image_id = yield from bot._client.upload_image(image_data, filename=filename) 465 - yield from bot._client.sendchatmessage(event.conv.id_, None, image_id=image_id) 466 - except Exception as e: 467 - yield from bot.coro_send_message(event.conv_id, "<i>error uploading screenshot</i>") 468 - logger.exception("upload failed".format(url)) 469 - 470 - 471 -def setintel(bot, event, *args): 472 - """set url for current converation for the screenshot command. 473 - use /bot clearintel to clear the previous url before setting a new one. 474 - """ 475 - url = bot.conversation_memory_get(event.conv_id, 'IntelURL') 476 - if url is None: 477 - bot.conversation_memory_set(event.conv_id, 'IntelURL', ''.join(args)) 478 - html = "<i><b>{}</b> updated screenshot URL".format(event.user.full_name) 479 - yield from bot.coro_send_message(event.conv, html) 480 - 481 - else: 482 - html = "<i><b>{}</b> URL already exists for this conversation!<br /><br />".format(event.user.full_name) 483 - html += "<i>Clear it first with /bot clearintel before setting a new one." 484 - yield from bot.coro_send_message(event.conv, html) 485 - 486 - 487 -def clearintel(bot, event, *args): 488 - """clear url for current converation for the screenshot command. 489 - """ 490 - url = bot.conversation_memory_get(event.conv_id, 'IntelURL') 491 - if url is None: 492 - html = "<i><b>{}</b> nothing to clear for this conversation".format(event.user.full_name) 493 - yield from bot.coro_send_message(event.conv, html) 494 - 495 - else: 496 - bot.conversation_memory_set(event.conv_id, 'IntelURL', None) 497 - html = "<i><b>{}</b> URL cleared for this conversation!<br />".format(event.user.full_name) 498 - yield from bot.coro_send_message(event.conv, html) 499 - 500 - 501 -def intel(bot, event, *args): 502 - """get a screenshot of a user provided URL or the default URL of the hangout. 503 - """ 504 - 505 - if args: 506 - if len(args) > 1: 507 - url = ' '.join(str(i) for i in args) 508 - else: 509 - url = args[0] 510 - else: 511 - url = bot.conversation_memory_get(event.conv_id, 'IntelURL') 512 - 513 - if bot.config.exists(["intel_screenbot", "SACSID"]): 514 - SACSID = bot.config.get_by_path(["intel_screenbot", "SACSID"]) 515 - else: 516 - html = "<i><b>{}</b> No Intel SACSID Cookie has been added to config. Unable to authenticate".format(event.user.full_name) 517 - yield from bot.coro_send_message(event.conv, html) 518 - if bot.config.exists(["intel_screenbot", "CSRF"]): 519 - CSRF = bot.config.get_by_path(["intel_screenbot", "CSRF"]) 520 - else: 521 - html = "<i><b>{}</b> No Intel CSRF Cookie has been added to config. Unable to authenticate".format(event.user.full_name) 522 - yield from bot.coro_send_message(event.conv, html) 523 - 524 - if url is None: 525 - html = "<i><b>{}</b> No Intel URL has been set for screenshots.".format(event.user.full_name) 526 - yield from bot.coro_send_message(event.conv, html) 527 - 528 - else: 529 - if re.match(r'^[a-zA-Z]+://', url): 530 - search = False 531 - ZoomSearch = re.finditer(r"(?:&z=).*", url) 532 - for matchNum, zoomlevel_raw in enumerate(ZoomSearch): 533 - matchNum = matchNum + 1 534 - zoomlevel_clean = zoomlevel_raw.group() 535 - zoomlevel = zoomlevel_clean[3:][:2] 536 - if zoomlevel.isdigit(): 537 - yield from bot.coro_send_message(event.conv_id, "<i>intel map at zoom level "+ zoomlevel + " requested, please wait...</i>") 538 - else: 539 - yield from bot.coro_send_message(event.conv_id, "<i>intel map at last zoom level requested, please wait...</i>") 540 - else: 541 - search = url 542 - logger.info(search); 543 - url = 'https://www.ingress.com/intel' 544 - yield from bot.coro_send_message(event.conv_id, "<i>intel map is searching " + search + " and screenshooting as requested, please wait...</i>") 545 - filename = event.conv_id + "." + str(time.time()) +".png" 546 - filepath = tempfile.NamedTemporaryFile(prefix=event.conv_id, suffix=".png", delete=False).name 547 - logger.debug("temporary screenshot file: {}".format(filepath)) 548 - 549 - try: 550 - loop = asyncio.get_event_loop() 551 - image_data = yield from _screencap(url, filepath, filename, SACSID, CSRF, search, bot, event) 552 - except Exception as e: 553 - yield from bot.coro_send_message(event.conv_id, "<i>error getting screenshot</i>") 554 - logger.exception("screencap failed".format(url)) 555 - return 556 diff --git a/requirements.txt b/requirements.txt 557 new file mode 100644 558 index 0000000..9d981c3 559 --- /dev/null 560 +++ b/requirements.txt 561 @@ -0,0 +1,2 @@ 562 +bs4 563 +requests 564 diff --git a/screencap_iitc.js b/screencap_iitc.js 565 new file mode 100644 566 index 0000000..c9413db 567 --- /dev/null 568 +++ b/screencap_iitc.js 569 @@ -0,0 +1,278 @@ 570 +var system = require('system'); 571 +var args = system.args; 572 +var page = require('webpage').create(); 573 +var fs = require('fs'); 574 +if (args.length === 1) { 575 + console.log('Try to pass some args when invoking this script!'); 576 +} else { 577 + if (args.length === 6){ 578 + var SACSID = args[1]; 579 + var CSRF = args[2]; 580 + var IntelURL = args[3]; 581 + var filepath = args[4]; 582 + var plugins_file = args[5]; 583 + var search = 'nix'; 584 + }else{ 585 + if (args.length === 7){ 586 + var SACSID = args[1]; 587 + var CSRF = args[2]; 588 + var IntelURL = args[3]; 589 + var filepath = args[4]; 590 + var search = args[5]; 591 + var plugins_file = args[6]; 592 + } 593 + } 594 +} 595 + 596 +function addCookies(sacsid, csrf) { 597 + phantom.addCookie({ 598 + name: 'SACSID', 599 + value: sacsid, 600 + domain: 'www.ingress.com', 601 + path: '/', 602 + httponly: true, 603 + secure: true 604 + }); 605 + phantom.addCookie({ 606 + name: 'csrftoken', 607 + value: csrf, 608 + domain: 'www.ingress.com', 609 + path: '/' 610 + }); 611 +} 612 + 613 + 614 +function waitFor ($config) { 615 + $config._start = $config._start || new Date(); 616 + if ($config.timeout && new Date - $config._start > $config.timeout) { 617 + if ($config.error) $config.error(); 618 + if ($config.debug) console.log('timedout ' + (new Date - $config._start) + 'ms'); 619 + return; 620 + } 621 + if ($config.check()) { 622 + if ($config.debug) console.log('success ' + (new Date - $config._start) + 'ms'); 623 + return $config.success(); 624 + } 625 + setTimeout(waitFor, $config.interval || 0, $config); 626 +} 627 + 628 +function loadIitcPlugin(src) { 629 + page.evaluate(function(src) { 630 + var script = document.createElement('script'); 631 + script.type='text/javascript'; 632 + script.src=src; 633 + document.head.insertBefore(script, document.head.lastChild); 634 + }, src); 635 +} 636 + 637 +function loadLocalIitcPlugin(src) { 638 + page.injectJs(src) 639 +} 640 + 641 +addCookies(SACSID, CSRF); 642 +afterCookieLogin(IntelURL, search); 643 + 644 +function afterCookieLogin(IntelURL, search) { 645 + page.viewportSize = { width: '1920', height: '1080' }; 646 + page.open(IntelURL, function(status) { 647 + if (status !== 'success') {quit('unable to connect to remote server')} 648 + page.injectJs('https://code.jquery.com/jquery-3.1.1.min.js'); 649 + setTimeout(function() { 650 + page.evaluate(function() { 651 + localStorage['ingress.intelmap.layergroupdisplayed'] = JSON.stringify({ 652 + "Unclaimed Portals":Boolean(1 === 1), 653 + "Level 1 Portals":Boolean(1 === 1), 654 + "Level 2 Portals":Boolean((1 <= 2) && (8 >= 2)), 655 + "Level 3 Portals":Boolean((1 <= 3) && (8 >= 3)), 656 + "Level 4 Portals":Boolean((1 <= 4) && (8 >= 4)), 657 + "Level 5 Portals":Boolean((1 <= 5) && (8 >= 5)), 658 + "Level 6 Portals":Boolean((1 <= 6) && (8 >= 6)), 659 + "Level 7 Portals":Boolean((1 <= 7) && (8 >= 7)), 660 + "Level 8 Portals":Boolean(8 === 8), 661 + "DEBUG Data Tiles":false, 662 + "Artifacts":true, 663 + "Ornaments":true 664 + }); 665 + var script = document.createElement('script'); 666 + script.type='text/javascript'; 667 + script.src='https://secure.jonatkins.com/iitc/release/total-conversion-build.user.js'; 668 + document.head.insertBefore(script, document.head.lastChild); 669 + }); 670 + loadIitcPlugin('http://iitc.jonatkins.com/release/plugins/canvas-render.user.js'); 671 + var plugins = JSON.parse(fs.read(plugins_file)); 672 + for(var i in plugins){ 673 + var plugin = plugins[i]; 674 + if(plugin.match('^[a-zA-Z]+://')){ 675 + loadIitcPlugin(plugin); 676 + }else{ 677 + loadLocalIitcPlugin(plugin); 678 + } 679 + } 680 + setTimeout(function() { 681 + if (search != "nix") { 682 + page.evaluate(function(search) { 683 + if (document.querySelector('#search')){ 684 + window.setTimeout(function() { 685 + document.getElementById("search").value=search; 686 + var e = jQuery.Event("keypress"); 687 + e.which = 13; 688 + e.keyCode = 13; 689 + $("#search").trigger(e); 690 + }, 2000); 691 + var checkExist = setInterval(function() { 692 + if ($('.searchquery').length > 0) { 693 + window.setTimeout(function() {$('.searchquery > :nth-child(2)').children()[0].click();}, 1000); 694 + clearInterval(checkExist); 695 + } 696 + }, 100); 697 + } 698 + }, search); 699 + } 700 + waitFor({ 701 + timeout: 120000, 702 + check: function () { 703 + return page.evaluate(function() { 704 + if (document.querySelector('.map').textContent.indexOf('done') != -1) { 705 + return true; 706 + }else{ 707 + return false; 708 + } 709 + }); 710 + }, 711 + success: function () { 712 + hideDebris(); 713 + prepare('1920', '1080'); 714 + main(); 715 + }, 716 + error: function () { 717 + hideDebris(); 718 + prepare('1920', '1080'); 719 + main(); 720 + } 721 + }); 722 + }, "5000"); 723 + }, "5000"); 724 + }); 725 +} 726 + 727 +function s(file) { 728 + page.render(file); 729 + phantom.exit(0); 730 +} 731 + 732 +function hideDebris() { 733 + window.setTimeout(function() { 734 + page.evaluate(function() { 735 + if (document.querySelector('#chat')) {document.querySelector('#chat').style.display = 'none';} 736 + if (document.querySelector('#chatcontrols')) {document.querySelector('#chatcontrols').style.display = 'none';} 737 + if (document.querySelector('#chatinput')) {document.querySelector('#chatinput').style.display = 'none';} 738 + if (document.querySelector('#updatestatus')) {document.querySelector('#updatestatus').style.display = 'none';} 739 + if (document.querySelector('#sidebartoggle')) {document.querySelector('#sidebartoggle').style.display = 'none';} 740 + if (document.querySelector('#scrollwrapper')) {document.querySelector('#scrollwrapper').style.display = 'none';} 741 + if (document.querySelector('.leaflet-control-container')) {document.querySelector('.leaflet-control-container').style.display = 'none';} 742 + }); 743 + }, 2000); 744 +} 745 + 746 +function prepare(widthz, heightz) { 747 + window.setTimeout(function() { 748 + page.evaluate(function(w, h) { 749 + $("span:contains(' Google Roads')").prev().click(); 750 + var water = document.createElement('p'); 751 + water.id='viewport-ice'; 752 + water.style.position = 'absolute'; 753 + water.style.top = '0'; 754 + water.style.marginTop = '0'; 755 + water.style.paddingTop = '0'; 756 + water.style.left = '0'; 757 + water.style.width = w + 'px'; 758 + water.style.height = h + 'px'; 759 + document.querySelectorAll('body')[0].appendChild(water); 760 + }, widthz, heightz); 761 + var selector = "#viewport-ice"; 762 + setElementBounds(selector); 763 + }, 4000); 764 +} 765 + 766 + 767 +function setElementBounds(selector) { 768 + page.clipRect = page.evaluate(function(selector) { 769 + var clipRect = document.querySelector(selector).getBoundingClientRect(); 770 + return { 771 + top: clipRect.top, 772 + left: clipRect.left, 773 + width: clipRect.width, 774 + height: clipRect.height 775 + }; 776 + }, selector); 777 +} 778 + 779 +function getDateTime(format) { 780 + var now = new Date(); 781 + var year = now.getFullYear(); 782 + var month = now.getMonth()+1; 783 + var day = now.getDate(); 784 + var hour = now.getHours(); 785 + var minute = now.getMinutes(); 786 + var second = now.getSeconds(); 787 + var timeZone = ''; 788 + if(month.toString().length === 1) { 789 + month = '0' + month; 790 + } 791 + if(day.toString().length === 1) { 792 + day = '0' + day; 793 + } 794 + if(hour.toString().length === 1) { 795 + hour = '0' + hour; 796 + } 797 + if(minute.toString().length === 1) { 798 + minute = '0' + minute; 799 + } 800 + if(second.toString().length === 1) { 801 + second = '0' + second; 802 + } 803 + var dateTime; 804 + if (format === 1) { 805 + dateTime = year + '-' + month + '-' + day + '--' + hour + '-' + minute + '-' + second; 806 + } else { 807 + dateTime = day + '.' + month + '.' + year + ' ' + hour + ':' + minute + ':' + second + timeZone; 808 + } 809 + return dateTime; 810 +} 811 + 812 +function addTimestamp(time) { 813 + page.evaluate(function(dateTime) { 814 + var water = document.createElement('p'); 815 + water.id='watermark-ice'; 816 + water.innerHTML = dateTime; 817 + water.style.position = 'absolute'; 818 + water.style.color = '#3A539B'; 819 + water.style.top = '0'; 820 + water.style.zIndex = '4404'; 821 + water.style.marginTop = '0'; 822 + water.style.paddingTop = '0'; 823 + water.style.left = '0'; 824 + water.style.fontSize = '40px'; 825 + water.style.opacity = '0.8'; 826 + water.style.fontFamily = 'monospace'; 827 + water.style.textShadow = 'rgb(3, 3, 3) 7px 5px 9px'; 828 + document.querySelectorAll('body')[0].appendChild(water); 829 + }, time); 830 +} 831 + 832 +/** 833 + * Main function. 834 + */ 835 +function main() { 836 + page.evaluate(function() { 837 + if (document.getElementById('watermark-ice')) { 838 + var oldStamp = document.getElementById('watermark-ice'); 839 + oldStamp.parentNode.removeChild(oldStamp); 840 + } 841 + }); 842 + window.setTimeout(function() { 843 + addTimestamp(getDateTime(0)); 844 + file = filepath; 845 + s(file); 846 + }, 3000); 847 +} 848 diff --git a/intel_screenbot/screencap.js b/screencap_intel.js 849 similarity index 55% 850 rename from intel_screenbot/screencap.js 851 rename to screencap_intel.js 852 index 9383f15..3ef8afc 100644 853 --- a/intel_screenbot/screencap.js 854 +++ b/screencap_intel.js 855 @@ -1,5 +1,5 @@ 856 var system = require('system') 857 -var args = require('system').args; 858 +var args = system.args; 859 var page = require('webpage').create(); 860 var fs = require('fs'); 861 if (args.length === 1) { 862 @@ -18,31 +18,12 @@ if (args.length === 1) { 863 var IntelURL = args[3]; 864 var filepath = args[4]; 865 var search = args[5]; 866 - console.log(search) 867 - system.stdout.writeLine(filepath); 868 } 869 } 870 } 871 872 -addCookies(SACSID,CSRF) 873 -afterCookieLogin(IntelURL, search) 874 - 875 -function waitFor ($config) { 876 - $config._start = $config._start || new Date(); 877 - 878 - if ($config.timeout && new Date - $config._start > $config.timeout) { 879 - if ($config.error) $config.error(); 880 - if ($config.debug) console.log('timedout ' + (new Date - $config._start) + 'ms'); 881 - return; 882 - } 883 - 884 - if ($config.check()) { 885 - if ($config.debug) console.log('success ' + (new Date - $config._start) + 'ms'); 886 - return $config.success(); 887 - } 888 - 889 - setTimeout(waitFor, $config.interval || 0, $config); 890 -} 891 +addCookies(SACSID,CSRF); 892 +afterCookieLogin(IntelURL, search); 893 894 function addCookies(sacsid, csrf) { 895 phantom.addCookie({ 896 @@ -61,26 +42,30 @@ function addCookies(sacsid, csrf) { 897 }); 898 } 899 900 +function waitFor ($config) { 901 + $config._start = $config._start || new Date(); 902 + if ($config.timeout && new Date - $config._start > $config.timeout) { 903 + if ($config.error) $config.error(); 904 + if ($config.debug) console.log('timedout ' + (new Date - $config._start) + 'ms'); 905 + return; 906 + } 907 + if ($config.check()) { 908 + if ($config.debug) console.log('success ' + (new Date - $config._start) + 'ms'); 909 + return $config.success(); 910 + } 911 + setTimeout(waitFor, $config.interval || 0, $config); 912 +} 913 914 -/** 915 - * Does all stuff needed after cookie authentication 916 - * @since 3.1.0 917 - */ 918 function afterCookieLogin(IntelURL, search) { 919 page.open(IntelURL, function(status) { 920 if (status !== 'success') {quit('unable to connect to remote server')} 921 922 - if(!isSignedIn()) { 923 - if(fs.exists('.iced_cookies')) { 924 - fs.remove('.iced_cookies'); 925 - } 926 - } 927 setTimeout(function() { 928 waitFor({ 929 timeout: 120000, 930 check: function () { 931 return page.evaluate(function() { 932 - if (document.querySelector('#percent_text').textContent == "90") { 933 + if (document.querySelector('#percent_text').textContent.indexOf('90') != -1) { 934 if (!document.getElementById("loading_msg").style.display){ 935 return true; 936 }else{ 937 @@ -100,91 +85,58 @@ function afterCookieLogin(IntelURL, search) { 938 main(); 939 }, 940 error: function () { 941 - system.stdout.writeLine('map did not finish loading in time...'); 942 page.evaluate(function() { 943 document.querySelector("#filters_container").style.display= 'none'; 944 }); 945 hideDebris(); 946 prepare('1920', '1080', search); 947 main(); 948 - } // optional 949 + } 950 }); 951 }, "5000"); 952 }); 953 } 954 955 -/** 956 - * Checks if user is signed in by looking for the "Sign in" button 957 - * @returns {boolean} 958 - * @since 3.2.0 959 - */ 960 -function isSignedIn() { 961 - return page.evaluate(function() { 962 - return document.getElementsByTagName('a')[0].innerText.trim() !== 'Sign in'; 963 - }); 964 -} 965 - 966 -function storeCookies() { 967 - var cookies = page.cookies; 968 - fs.write('.iced_cookies', '', 'w'); 969 - for(var i in cookies) { 970 - fs.write('.iced_cookies', cookies[i].name + '=' + cookies[i].value +'\n', 'a'); 971 - } 972 -} 973 - 974 function s(file) { 975 page.render(file); 976 phantom.exit(0); 977 } 978 979 function hideDebris() { 980 - system.stdout.writeLine('hideDebris...'); 981 - page.evaluate(function() { 982 - if (document.querySelector('#comm')) {document.querySelector('#comm').style.display = 'none';} 983 - if (document.querySelector('#player_stats')) {document.querySelector('#player_stats').style.display = 'none';} 984 - if (document.querySelector('#game_stats')) {document.querySelector('#game_stats').style.display = 'none';} 985 - if (document.querySelector('#geotools')) {document.querySelector('#geotools').style.display = 'none';} 986 - if (document.querySelector('#header')) {document.querySelector('#header').style.display = 'none';} 987 - if (document.querySelector('#snapcontrol')) {document.querySelector('#snapcontrol').style.display = 'none';} 988 - if (document.querySelectorAll('.img_snap')[0]) {document.querySelectorAll('.img_snap')[0].style.display = 'none';} 989 - if (document.querySelector('#display_msg_text')) {document.querySelector('#display_msg_text').style.display = 'none';} 990 - }); 991 - page.evaluate(function() { 992 - var hide = document.querySelectorAll('.gmnoprint'); 993 - for (var index = 0; index < hide.length; ++index) { 994 - hide[index].style.display = 'none'; 995 - } 996 - }); 997 + page.evaluate(function() { 998 + if (document.querySelector('#comm')) {document.querySelector('#comm').style.display = 'none';} 999 + if (document.querySelector('#player_stats')) {document.querySelector('#player_stats').style.display = 'none';} 1000 + if (document.querySelector('#game_stats')) {document.querySelector('#game_stats').style.display = 'none';} 1001 + if (document.querySelector('#geotools')) {document.querySelector('#geotools').style.display = 'none';} 1002 + if (document.querySelector('#header')) {document.querySelector('#header').style.display = 'none';} 1003 + if (document.querySelector('#snapcontrol')) {document.querySelector('#snapcontrol').style.display = 'none';} 1004 + if (document.querySelectorAll('.img_snap')[0]) {document.querySelectorAll('.img_snap')[0].style.display = 'none';} 1005 + if (document.querySelector('#display_msg_text')) {document.querySelector('#display_msg_text').style.display = 'none';} 1006 + }); 1007 + page.evaluate(function() { 1008 + var hide = document.querySelectorAll('.gmnoprint'); 1009 + for (var index = 0; index < hide.length; ++index) { 1010 + hide[index].style.display = 'none'; 1011 + } 1012 + }); 1013 } 1014 1015 -/** 1016 - * Prepare map for screenshooting. Make screenshots same width and height with map_canvas 1017 - * If IITC, also set width and height 1018 - * @param {boolean} iitcz 1019 - * @param {number} widthz 1020 - * @param {number} heightz 1021 - */ 1022 function prepare(widthz, heightz, search) { 1023 - system.stdout.writeLine('prepare...'); 1024 - if (search == "nix") { 1025 - var selector = "#map_canvas"; 1026 - setElementBounds(selector); 1027 - }else{ 1028 - page.evaluate(function(search) { 1029 - if (document.querySelector('#geocode')){ 1030 - document.getElementById("address").value=search; 1031 - document.querySelector("input[value=Search]").click(); 1032 - } 1033 - }, search); 1034 - var selector = "#map_canvas"; 1035 - setElementBounds(selector); 1036 - } 1037 + if (search == "nix") { 1038 + var selector = "#map_canvas"; 1039 + setElementBounds(selector); 1040 + }else{ 1041 + page.evaluate(function(search) { 1042 + if (document.querySelector('#geocode')){ 1043 + document.getElementById("address").value=search; 1044 + document.querySelector("input[value=Search]").click(); 1045 + } 1046 + }, search); 1047 + var selector = "#map_canvas"; 1048 + setElementBounds(selector); 1049 + } 1050 } 1051 1052 -/** 1053 - * Sets element bounds 1054 - * @param selector 1055 - */ 1056 function setElementBounds(selector) { 1057 page.clipRect = page.evaluate(function(selector) { 1058 var clipRect = document.querySelector(selector).getBoundingClientRect(); 1059 @@ -197,10 +149,6 @@ function setElementBounds(selector) { 1060 }, selector); 1061 } 1062 1063 -/** 1064 - * Checks if human presence not detected and makes a human present 1065 - * @since 2.3.0 1066 - */ 1067 function humanPresence() { 1068 var outside = page.evaluate(function() { 1069 return !!(document.getElementById('butterbar') && (document.getElementById('butterbar').style.display !== 'none')); 1070 @@ -247,37 +195,34 @@ function getDateTime(format) { 1071 } 1072 1073 function addTimestamp(time) { 1074 - page.evaluate(function(dateTime) { 1075 - var water = document.createElement('p'); 1076 - water.id='watermark-ice'; 1077 - water.innerHTML = dateTime; 1078 - water.style.position = 'absolute'; 1079 - water.style.color = 'orange'; 1080 - water.style.top = '0'; 1081 - water.style.left = '0'; 1082 - water.style.fontSize = '40px'; 1083 - water.style.opacity = '0.8'; 1084 - water.style.marginTop = '0'; 1085 - water.style.paddingTop = '0'; 1086 - water.style.fontFamily = 'monospace'; 1087 - water.style.textShadow = '2px 2px 5px #111717'; 1088 - document.querySelector('#map_canvas').appendChild(water); 1089 - }, time); 1090 + page.evaluate(function(dateTime) { 1091 + var water = document.createElement('p'); 1092 + water.id='watermark-ice'; 1093 + water.innerHTML = dateTime; 1094 + water.style.position = 'absolute'; 1095 + water.style.color = 'orange'; 1096 + water.style.top = '0'; 1097 + water.style.left = '0'; 1098 + water.style.fontSize = '40px'; 1099 + water.style.opacity = '0.8'; 1100 + water.style.marginTop = '0'; 1101 + water.style.paddingTop = '0'; 1102 + water.style.fontFamily = 'monospace'; 1103 + water.style.textShadow = '2px 2px 5px #111717'; 1104 + document.querySelector('#map_canvas').appendChild(water); 1105 + }, time); 1106 } 1107 1108 /** 1109 * Main function. 1110 */ 1111 function main() { 1112 - system.stdout.writeLine('main...'); 1113 - if (true){ 1114 - page.evaluate(function() { 1115 - if (document.getElementById('watermark-ice')) { 1116 - var oldStamp = document.getElementById('watermark-ice'); 1117 - oldStamp.parentNode.removeChild(oldStamp); 1118 - } 1119 - }); 1120 - } 1121 + page.evaluate(function() { 1122 + if (document.getElementById('watermark-ice')) { 1123 + var oldStamp = document.getElementById('watermark-ice'); 1124 + oldStamp.parentNode.removeChild(oldStamp); 1125 + } 1126 + }); 1127 humanPresence(); 1128 window.setTimeout(function() { 1129 addTimestamp(getDateTime(0));