intel-screenbot

An Ingress Intel Map Bot for Hangoutsbot
git clone git://archive.git.mtrnord.blog/MTRNord/intel-screenbot.git
Log | Files | Refs | README | LICENSE

commit 1d357588db71a999d9c2056593691a2544e2ee2f
parent c061ac3ee83c9e755c0f3ed3e4aab735d5dab937
Author: Marcel <MTRNord@users.noreply.github.com>
Date:   Mon, 14 Nov 2016 20:14:17 +0100

Merge pull request #1 from MTRNord/iitc

Add IITC and completely rework Repository
Diffstat:
MREADME.md | 56++++++++++++++++++++++++++++++++++++++++++++++++--------
A__init__.py | 315+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dintel_screenbot/__init__.py | 136-------------------------------------------------------------------------------
Dintel_screenbot/screencap.js | 287-------------------------------------------------------------------------------
Arequirements.txt | 2++
Ascreencap_iitc.js | 278+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascreencap_intel.js | 232+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 875 insertions(+), 431 deletions(-)

diff --git a/README.md b/README.md @@ -11,18 +11,23 @@ Get and post a screenshot of the Intel Map. ## Install To install the plugin you need to: -1. Clone this repo into `<yourBotDir>/plugins/` -2. Optional remove `README.md` `LICENSE` and `.gitignore` -3. Follow Configuration. +1. Go into `<yourBotDir>/plugins/` +2. Clone this repo into `intel_screenbot` +3. Optional remove `README.md` `LICENSE` and `.gitignore` from `<yourBotDir>/plugins/intel_screenbot` +4. Run `pip3 install -r requirements.txt` +5. Follow Configuration. ## Configuration For using the Intel Screenbot you need to add the following to the config.json: ``` "intel_screenbot": { - "SACSID": "YOUR SACSID", - "CSRF": "YOUR CSRF" - } + "SACSID": "YOUR SACSID", + "CSRF": "YOUR CSRF", + "plugin_dirs": [ + "http://iitc.jonatkins.com/release/plugins" + ] + } ``` According to the official INSTALL Documention of the hangoutbot you will find the config.json in `/<username>/.local/share/hangupsbot/` @@ -30,6 +35,25 @@ According to the official INSTALL Documention of the hangoutbot you will find th Also you need to add `intel_screenbot` to the plugins. +## How to add gitlab to plugin_dirs + +1. Open in browser: `https://gitlab.com/api/v3/projects/search/:REPO_NAME` +2. copy the number in `id` +3. add `http://gitlab.com/api/v3/projects/:ID/repository/tree` to `plugin_dirs` +4. add `"gitlab_token":"YOUR_GITLAB_API_TOKEN"` to `intel_screenbot` + +*Note: repos are currently locked to master branch* + +## How to add github to plugins_dir + +1. add `https://api.github.com/repos/:REPO_USER/:REPO_NAME/git/trees/master?recursive=1` + +## How to add local files to plugins_dir + +1. just add the absolute path to `plugins_dir` (relative paths are not tested) + +*Note: repos are currently locked to master branch* + ## How to get SACSID and CSRF You should look at the Documentation of [ingress-ice](https://github.com/nibogd/ingress-ice/wiki/Cookies-Authentication) @@ -41,13 +65,29 @@ You should look at the Documentation of [ingress-ice](https://github.com/nibogd/ `/bot clearintel` * Clears the default screenshot URL of a particular hangout. +`/bot show_iitcplugins` +* Shows every availible IITC-plugin. + +`/bot set_iitcplugins <plugin names devided by whitespace>` +* Sets the plugins to use with IITC per hangout. + +`/bot clear_iitcplugins` +* Clear the plugins to use with IITC per hangout. + + ## User Command -`/bot intel [<url>]` +`/bot intel [<url> or <searchTerm>]` * Provide an arbitrary `<url>` to take a screenshot * If no `<url>` is supplied, use the default screenshot URL (or reply with an error if no URL is set) -## PhantomJS Installation +`/bot iitc [<url> or <searchTerm>]` +* Provide an arbitrary `<url>` to take a screenshot +* If no `<url>` is supplied, use the default screenshot URL (or reply with an error if no URL is set) + +## PhantomJS Installation + +*May be outdated* ### Debian-based distros (e.g. Ubuntu 14.04) diff --git a/__init__.py b/__init__.py @@ -0,0 +1,315 @@ +from bs4 import BeautifulSoup +import requests +import json +import asyncio, io, logging, os, re, time, tempfile +import subprocess +import plugins +import re +from asyncio import subprocess +from shutil import move +from os import remove, close + +logger = logging.getLogger(__name__) + + +def _initialise(bot): + plugins.register_user_command(["intel", "iitc"]) + plugins.register_admin_command(["setintel", "clearintel", "show_iitcplugins", "set_iitcplugins", "clear_iitcplugins"]) + _get_iitc_plugins(bot) + + +@asyncio.coroutine +def _open_file(name): + logger.debug("opening screenshot file: {}".format(name)) + return open(name, 'rb') + +def _parse_onlineRepos(url, ext=''): + logger.debug("parsing github or gitlab or http(s)") + page = requests.get(url).text + if 'gitlab.com' in url: + files = [] + for json_page in json.loads(page): + for attribute, value in json_page.items(): + if attribute == "name": + if value.endswith(ext): + files.append(url.replace("/tree/", "/blobs/master") + "&filepath=" + value) + return files + elif 'github.com' in url: + files = [] + for attribute, value in json.loads(page).items(): + if attribute == "tree": + for tree in value: + for attribute, value in tree.items(): + if attribute == "path": + if value.endswith(ext): + files.append(url.replace("https://api.github.com/repos/", "https://raw.githubusercontent.com/").replace("git/trees/",'').replace("master?recursive=1","master/") + value) + return files + else: + soup = BeautifulSoup(page, 'html.parser') + return [url + '/' + node.get('href') for node in soup.find_all('a') if node.get('href').endswith(ext)] + +def _get_iitc_plugins(bot): + logger.debug("getting availible plugins") + if bot.config.exists(["intel_screenbot", "gitlab_token"]): + token = bot.config.get_by_path(["intel_screenbot", "gitlab_token"]) + url_config = bot.config.get_by_path(["intel_screenbot", "plugin_dirs"]) + ext = '.user.js' + data=[] + for url in url_config: + if ext in url: + item = {"name": url.split('/', url.count('/'))[-1].replace(ext, ''), "url": url} + data.append(item) + else: + if "gitlab.com" in url: + url = url + '?private_token=' + token + for file in _parse_onlineRepos(url, ext): + if "gitlab.com" in url: + item = {"name": file.split('=', file.count('='))[-1].replace(ext, ''), "url": file} + elif 'github.com' in url: + item = {"name": file.split('/', file.count('/'))[-1].replace(ext, ''), "url": file} + else: + item = {"name": file.split('/', file.count('/'))[-1].replace(ext, ''), "url": file} + data.append(item) + + iitc_plugins = data + if bot.memory.exists(["iitc_plugins"]): + bot.memory.pop_by_path(["iitc_plugins"]) + bot.memory.set_by_path(["iitc_plugins"], iitc_plugins) + else: + bot.memory.set_by_path(["iitc_plugins"], iitc_plugins) + +@asyncio.coroutine +def _get_lines(shell_command): + p = yield from asyncio.create_subprocess_shell(shell_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + stdout, stderr = yield from p.communicate() + return p.returncode, stdout + +@asyncio.coroutine +def _screencap(maptype, url, filepath, filename, SACSID, CSRF, plugins, search, bot, event): + loop = asyncio.get_event_loop() + logger.info("screencapping {} and saving as {}".format(url, filepath)) + if plugins is '': + if search == False: + command = 'phantomjs hangupsbot/plugins/intel_screenbot/screencap_' + maptype + '.js "' + SACSID + '" "' + CSRF + '" "' + url + '" "' + filepath + '"' + task = _get_lines(command) + task = asyncio.wait_for(task, 180.0, loop=self.loop) + exitcode, stdout = loop.run_until_complete(task) + else: + command = 'phantomjs hangupsbot/plugins/intel_screenbot/screencap_' + maptype + '.js "' + SACSID + '" "' + CSRF + '" "' + url + '" "' + filepath + '" "' + search + '"' + task = _get_lines(command) + task = asyncio.wait_for(task, 180.0, loop=loop) + exitcode, stdout = yield from task + else: + if search == False: + command = 'phantomjs hangupsbot/plugins/intel_screenbot/screencap_' + maptype + '.js "' + SACSID + '" "' + CSRF + '" "' + url + '" "' + filepath + '" "' + plugins + '"' + task = _get_lines(command) + task = asyncio.wait_for(task, 180.0, loop=self.loop) + exitcode, stdout = loop.run_until_complete(task) + else: + command = 'phantomjs hangupsbot/plugins/intel_screenbot/screencap_' + maptype + '.js "' + SACSID + '" "' + CSRF + '" "' + url + '" "' + filepath + '" "' + search + '" "' + plugins + '"' + task = _get_lines(command) + task = asyncio.wait_for(task, 180.0, loop=loop) + exitcode, stdout = yield from task + + # read the resulting file into a byte array + file_resource = yield from _open_file(filepath) + file_data = yield from loop.run_in_executor(None, file_resource.read) + image_data = yield from loop.run_in_executor(None, io.BytesIO, file_data) + try: + image_id = yield from bot._client.upload_image(image_data, filename=filename) + yield from bot._client.sendchatmessage(event.conv.id_, None, image_id=image_id) + except Exception as e: + yield from bot.coro_send_message(event.conv_id, "<i>error uploading screenshot</i>") + logger.exception("upload failed".format(url)) + + +def setintel(bot, event, *args): + """set url for current converation for the intel or iitc command. + use /bot clearintel to clear the previous url before setting a new one. + """ + url = bot.conversation_memory_get(event.conv_id, 'IntelURL') + if url is None: + bot.conversation_memory_set(event.conv_id, 'IntelURL', ''.join(args)) + html = "<i><b>{}</b> updated screenshot URL".format(event.user.full_name) + yield from bot.coro_send_message(event.conv, html) + + else: + html = "<i><b>{}</b> URL already exists for this conversation!<br /><br />".format(event.user.full_name) + html += "<i>Clear it first with /bot clearintel before setting a new one." + yield from bot.coro_send_message(event.conv, html) + + +def clearintel(bot, event, *args): + """clear url for current converation for the intel or iitc command. + """ + url = bot.conversation_memory_get(event.conv_id, 'IntelURL') + if url is None: + html = "<i><b>{}</b> nothing to clear for this conversation".format(event.user.full_name) + yield from bot.coro_send_message(event.conv, html) + + else: + bot.conversation_memory_set(event.conv_id, 'IntelURL', None) + html = "<i><b>{}</b> URL cleared for this conversation!<br />".format(event.user.full_name) + yield from bot.coro_send_message(event.conv, html) + + +def intel(bot, event, *args): + """get a screenshot of a search term or intel URL or the default intel URL of the hangout. + """ + + if args: + if len(args) > 1: + url = ' '.join(str(i) for i in args) + else: + url = args[0] + if '"' in url: + url = url.replace('"', '') + else: + url = bot.conversation_memory_get(event.conv_id, 'IntelURL') + + if bot.config.exists(["intel_screenbot", "SACSID"]): + SACSID = bot.config.get_by_path(["intel_screenbot", "SACSID"]) + else: + html = "<i><b>{}</b> No Intel SACSID Cookie has been added to config. Unable to authenticate".format(event.user.full_name) + yield from bot.coro_send_message(event.conv, html) + if bot.config.exists(["intel_screenbot", "CSRF"]): + CSRF = bot.config.get_by_path(["intel_screenbot", "CSRF"]) + else: + html = "<i><b>{}</b> No Intel CSRF Cookie has been added to config. Unable to authenticate".format(event.user.full_name) + yield from bot.coro_send_message(event.conv, html) + + if url is None: + html = "<i><b>{}</b> No Intel URL or search term has been set for screenshots.".format(event.user.full_name) + yield from bot.coro_send_message(event.conv, html) + + else: + if re.match(r'^[a-zA-Z]+://', url): + search = False + ZoomSearch = re.finditer(r"(?:&z=).*", url) + for matchNum, zoomlevel_raw in enumerate(ZoomSearch): + matchNum = matchNum + 1 + zoomlevel_clean = zoomlevel_raw.group() + zoomlevel = zoomlevel_clean[3:][:2] + if zoomlevel.isdigit(): + yield from bot.coro_send_message(event.conv_id, "<i>intel map at zoom level "+ zoomlevel + " requested, please wait...</i>") + else: + yield from bot.coro_send_message(event.conv_id, "<i>intel map at last zoom level requested, please wait...</i>") + else: + search = url + logger.info(search); + url = 'https://www.ingress.com/intel' + yield from bot.coro_send_message(event.conv_id, "<i>intel map is searching " + search + " and screenshooting as requested, please wait...</i>") + + filename = event.conv_id + "." + str(time.time()) +".png" + filepath = tempfile.NamedTemporaryFile(prefix=event.conv_id, suffix=".png", delete=False).name + logger.debug("temporary screenshot file: {}".format(filepath)) + try: + loop = asyncio.get_event_loop() + image_data = yield from _screencap("intel", url, filepath, filename, SACSID, CSRF, "", search, bot, event) + except Exception as e: + yield from bot.coro_send_message(event.conv_id, "<i>error getting screenshot</i>") + logger.exception("screencap failed".format(url)) + return + + +def iitc(bot, event, *args): + """get a screenshot of a search term or intel URL or the default intel URL of the hangout. + """ + + if args: + if len(args) > 1: + url = ' '.join(str(i) for i in args) + else: + url = args[0] + if '"' in url: + url = url.replace('"', '') + else: + url = bot.conversation_memory_get(event.conv_id, 'IntelURL') + + if bot.config.exists(["intel_screenbot", "SACSID"]): + SACSID = bot.config.get_by_path(["intel_screenbot", "SACSID"]) + else: + html = "<i><b>{}</b> No Intel SACSID Cookie has been added to config. Unable to authenticate".format(event.user.full_name) + yield from bot.coro_send_message(event.conv, html) + if bot.config.exists(["intel_screenbot", "CSRF"]): + CSRF = bot.config.get_by_path(["intel_screenbot", "CSRF"]) + else: + html = "<i><b>{}</b> No Intel CSRF Cookie has been added to config. Unable to authenticate".format(event.user.full_name) + yield from bot.coro_send_message(event.conv, html) + + if url is None: + html = "<i><b>{}</b> No Intel URL has been set for screenshots.".format(event.user.full_name) + yield from bot.coro_send_message(event.conv, html) + + else: + if re.match(r'^[a-zA-Z]+://', url): + search = False + ZoomSearch = re.finditer(r"(?:&z=).*", url) + for matchNum, zoomlevel_raw in enumerate(ZoomSearch): + matchNum = matchNum + 1 + zoomlevel_clean = zoomlevel_raw.group() + zoomlevel = zoomlevel_clean[3:][:2] + if zoomlevel.isdigit(): + yield from bot.coro_send_message(event.conv_id, "<i>intel map at zoom level "+ zoomlevel + " requested, please wait...</i>") + else: + yield from bot.coro_send_message(event.conv_id, "<i>intel map at last zoom level requested, please wait...</i>") + else: + search = url + logger.info(search); + url = 'https://www.ingress.com/intel' + yield from bot.coro_send_message(event.conv_id, "<i>intel map is searching " + search + " and screenshooting as requested, please wait...</i>") + + filename = event.conv_id + "." + str(time.time()) +".png" + filepath = tempfile.NamedTemporaryFile(prefix=event.conv_id, suffix=".png", delete=False).name + plugins_filepath = tempfile.NamedTemporaryFile(prefix=event.conv_id, suffix=".json", delete=False).name + logger.debug("temporary screenshot file: {}".format(filepath)) + if bot.conversation_memory_get(event.conv_id, 'iitc_plugins'): + plugins = [] + plugin_names = bot.conversation_memory_get(event.conv_id, 'iitc_plugins').split(", ") + if bot.memory.exists(["iitc_plugins"]): + for plugin_objects in bot.memory.get_by_path(["iitc_plugins"]): + for plugin_name in plugin_names: + if plugin_objects["name"] == plugin_name: + plugins.append(plugin_objects["url"]) + else: + plugins = '' + + with open(plugins_filepath, 'w') as out: + out.write(json.dumps(plugins)) + + try: + loop = asyncio.get_event_loop() + image_data = yield from _screencap("iitc", url, filepath, filename, SACSID, CSRF, plugins_filepath, search, bot, event) + except Exception as e: + yield from bot.coro_send_message(event.conv_id, "<i>error getting screenshot</i>") + logger.exception("screencap failed".format(url)) + return + +def show_iitcplugins(bot, event, *args): + if bot.memory.exists(["iitc_plugins"]): + plugin_names = [] + for plugin_objects in bot.memory.get_by_path(["iitc_plugins"]): + for attribute, value in plugin_objects.items(): + if attribute == "name": + plugin_names.append(value) + 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)) + +def set_iitcplugins(bot, event, *args): + if not bot.conversation_memory_get(event.conv_id, 'iitc_plugins') is None: + html = "<i><b>{}</b> plugins already set for this conversation!<br /><br />".format(event.user.full_name) + html += "<i>Clear them first with /bot clear_iitcplugins before setting new ones." + yield from bot.coro_send_message(event.conv, html) + else: + bot.conversation_memory_set(event.conv_id, 'iitc_plugins', ', '.join(args)) + html = "<i><b>{}</b> updated plugins".format(event.user.full_name) + yield from bot.coro_send_message(event.conv, html) + +def clear_iitcplugins(bot, event, *args): + if bot.conversation_memory_get(event.conv_id, 'iitc_plugins') is None: + html = "<i><b>{}</b> nothing to clear for this conversation".format(event.user.full_name) + yield from bot.coro_send_message(event.conv, html) + + else: + bot.conversation_memory_set(event.conv_id, 'iitc_plugins', None) + html = "<i><b>{}</b> plugins cleared for this conversation!<br />".format(event.user.full_name) + yield from bot.coro_send_message(event.conv, html) diff --git a/intel_screenbot/__init__.py b/intel_screenbot/__init__.py @@ -1,136 +0,0 @@ -import asyncio, io, logging, os, re, time, tempfile -import subprocess -import plugins -import re -from asyncio import subprocess - -logger = logging.getLogger(__name__) - - -def _initialise(bot): - plugins.register_user_command(["intel"]) - plugins.register_admin_command(["setintel", "clearintel"]) - -@asyncio.coroutine -def _open_file(name): - logger.debug("opening screenshot file: {}".format(name)) - return open(name, 'rb') - -@asyncio.coroutine -def _get_lines(shell_command): - p = yield from asyncio.create_subprocess_shell(shell_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - stdout, stderr = yield from p.communicate() - return p.returncode, stdout - -@asyncio.coroutine -def _screencap(url, filepath, filename, SACSID, CSRF, search, bot, event): - loop = asyncio.get_event_loop() - logger.info("screencapping {} and saving as {}".format(url, filepath)) - if search == False: - command = 'phantomjs hangupsbot/plugins/intel_screenbot/screencap.js "' + SACSID + '" "' + CSRF + '" "' + url + '" "' + filepath + '"' - task = _get_lines(command) - task = asyncio.wait_for(task, 180.0, loop=self.loop) - exitcode, stdout = loop.run_until_complete(task) - else: - command = 'phantomjs hangupsbot/plugins/intel_screenbot/screencap.js "' + SACSID + '" "' + CSRF + '" "' + url + '" "' + filepath + '" "' + search + '"' - task = _get_lines(command) - task = asyncio.wait_for(task, 180.0, loop=loop) - exitcode, stdout = yield from task - - # read the resulting file into a byte array - file_resource = yield from _open_file(filepath) - file_data = yield from loop.run_in_executor(None, file_resource.read) - image_data = yield from loop.run_in_executor(None, io.BytesIO, file_data) - try: - image_id = yield from bot._client.upload_image(image_data, filename=filename) - yield from bot._client.sendchatmessage(event.conv.id_, None, image_id=image_id) - except Exception as e: - yield from bot.coro_send_message(event.conv_id, "<i>error uploading screenshot</i>") - logger.exception("upload failed".format(url)) - - -def setintel(bot, event, *args): - """set url for current converation for the screenshot command. - use /bot clearintel to clear the previous url before setting a new one. - """ - url = bot.conversation_memory_get(event.conv_id, 'IntelURL') - if url is None: - bot.conversation_memory_set(event.conv_id, 'IntelURL', ''.join(args)) - html = "<i><b>{}</b> updated screenshot URL".format(event.user.full_name) - yield from bot.coro_send_message(event.conv, html) - - else: - html = "<i><b>{}</b> URL already exists for this conversation!<br /><br />".format(event.user.full_name) - html += "<i>Clear it first with /bot clearintel before setting a new one." - yield from bot.coro_send_message(event.conv, html) - - -def clearintel(bot, event, *args): - """clear url for current converation for the screenshot command. - """ - url = bot.conversation_memory_get(event.conv_id, 'IntelURL') - if url is None: - html = "<i><b>{}</b> nothing to clear for this conversation".format(event.user.full_name) - yield from bot.coro_send_message(event.conv, html) - - else: - bot.conversation_memory_set(event.conv_id, 'IntelURL', None) - html = "<i><b>{}</b> URL cleared for this conversation!<br />".format(event.user.full_name) - yield from bot.coro_send_message(event.conv, html) - - -def intel(bot, event, *args): - """get a screenshot of a user provided URL or the default URL of the hangout. - """ - - if args: - if len(args) > 1: - url = ' '.join(str(i) for i in args) - else: - url = args[0] - else: - url = bot.conversation_memory_get(event.conv_id, 'IntelURL') - - if bot.config.exists(["intel_screenbot", "SACSID"]): - SACSID = bot.config.get_by_path(["intel_screenbot", "SACSID"]) - else: - html = "<i><b>{}</b> No Intel SACSID Cookie has been added to config. Unable to authenticate".format(event.user.full_name) - yield from bot.coro_send_message(event.conv, html) - if bot.config.exists(["intel_screenbot", "CSRF"]): - CSRF = bot.config.get_by_path(["intel_screenbot", "CSRF"]) - else: - html = "<i><b>{}</b> No Intel CSRF Cookie has been added to config. Unable to authenticate".format(event.user.full_name) - yield from bot.coro_send_message(event.conv, html) - - if url is None: - html = "<i><b>{}</b> No Intel URL has been set for screenshots.".format(event.user.full_name) - yield from bot.coro_send_message(event.conv, html) - - else: - if re.match(r'^[a-zA-Z]+://', url): - search = False - ZoomSearch = re.finditer(r"(?:&z=).*", url) - for matchNum, zoomlevel_raw in enumerate(ZoomSearch): - matchNum = matchNum + 1 - zoomlevel_clean = zoomlevel_raw.group() - zoomlevel = zoomlevel_clean[3:][:2] - if zoomlevel.isdigit(): - yield from bot.coro_send_message(event.conv_id, "<i>intel map at zoom level "+ zoomlevel + " requested, please wait...</i>") - else: - yield from bot.coro_send_message(event.conv_id, "<i>intel map at last zoom level requested, please wait...</i>") - else: - search = url - logger.info(search); - url = 'https://www.ingress.com/intel' - yield from bot.coro_send_message(event.conv_id, "<i>intel map is searching " + search + " and screenshooting as requested, please wait...</i>") - filename = event.conv_id + "." + str(time.time()) +".png" - filepath = tempfile.NamedTemporaryFile(prefix=event.conv_id, suffix=".png", delete=False).name - logger.debug("temporary screenshot file: {}".format(filepath)) - - try: - loop = asyncio.get_event_loop() - image_data = yield from _screencap(url, filepath, filename, SACSID, CSRF, search, bot, event) - except Exception as e: - yield from bot.coro_send_message(event.conv_id, "<i>error getting screenshot</i>") - logger.exception("screencap failed".format(url)) - return diff --git a/intel_screenbot/screencap.js b/intel_screenbot/screencap.js @@ -1,287 +0,0 @@ -var system = require('system') -var args = require('system').args; -var page = require('webpage').create(); -var fs = require('fs'); -if (args.length === 1) { - console.log('Try to pass some args when invoking this script!'); -} else { - if (args.length === 5){ - var SACSID = args[1]; - var CSRF = args[2]; - var IntelURL = args[3]; - var filepath = args[4]; - var search = 'nix'; - }else{ - if (args.length === 6){ - var SACSID = args[1]; - var CSRF = args[2]; - var IntelURL = args[3]; - var filepath = args[4]; - var search = args[5]; - console.log(search) - system.stdout.writeLine(filepath); - } - } -} - -addCookies(SACSID,CSRF) -afterCookieLogin(IntelURL, search) - -function waitFor ($config) { - $config._start = $config._start || new Date(); - - if ($config.timeout && new Date - $config._start > $config.timeout) { - if ($config.error) $config.error(); - if ($config.debug) console.log('timedout ' + (new Date - $config._start) + 'ms'); - return; - } - - if ($config.check()) { - if ($config.debug) console.log('success ' + (new Date - $config._start) + 'ms'); - return $config.success(); - } - - setTimeout(waitFor, $config.interval || 0, $config); -} - -function addCookies(sacsid, csrf) { - phantom.addCookie({ - name: 'SACSID', - value: sacsid, - domain: 'www.ingress.com', - path: '/', - httponly: true, - secure: true - }); - phantom.addCookie({ - name: 'csrftoken', - value: csrf, - domain: 'www.ingress.com', - path: '/' - }); -} - - -/** - * Does all stuff needed after cookie authentication - * @since 3.1.0 - */ -function afterCookieLogin(IntelURL, search) { - page.open(IntelURL, function(status) { - if (status !== 'success') {quit('unable to connect to remote server')} - - if(!isSignedIn()) { - if(fs.exists('.iced_cookies')) { - fs.remove('.iced_cookies'); - } - } - setTimeout(function() { - waitFor({ - timeout: 120000, - check: function () { - return page.evaluate(function() { - if (document.querySelector('#percent_text').textContent == "90") { - if (!document.getElementById("loading_msg").style.display){ - return true; - }else{ - return false; - } - }else{ - return false; - } - }); - }, - success: function () { - page.evaluate(function() { - document.querySelector("#filters_container").style.display= 'none'; - }); - hideDebris(); - prepare('1920', '1080', search); - main(); - }, - error: function () { - system.stdout.writeLine('map did not finish loading in time...'); - page.evaluate(function() { - document.querySelector("#filters_container").style.display= 'none'; - }); - hideDebris(); - prepare('1920', '1080', search); - main(); - } // optional - }); - }, "5000"); - }); -} - -/** - * Checks if user is signed in by looking for the "Sign in" button - * @returns {boolean} - * @since 3.2.0 - */ -function isSignedIn() { - return page.evaluate(function() { - return document.getElementsByTagName('a')[0].innerText.trim() !== 'Sign in'; - }); -} - -function storeCookies() { - var cookies = page.cookies; - fs.write('.iced_cookies', '', 'w'); - for(var i in cookies) { - fs.write('.iced_cookies', cookies[i].name + '=' + cookies[i].value +'\n', 'a'); - } -} - -function s(file) { - page.render(file); - phantom.exit(0); -} - -function hideDebris() { - system.stdout.writeLine('hideDebris...'); - page.evaluate(function() { - if (document.querySelector('#comm')) {document.querySelector('#comm').style.display = 'none';} - if (document.querySelector('#player_stats')) {document.querySelector('#player_stats').style.display = 'none';} - if (document.querySelector('#game_stats')) {document.querySelector('#game_stats').style.display = 'none';} - if (document.querySelector('#geotools')) {document.querySelector('#geotools').style.display = 'none';} - if (document.querySelector('#header')) {document.querySelector('#header').style.display = 'none';} - if (document.querySelector('#snapcontrol')) {document.querySelector('#snapcontrol').style.display = 'none';} - if (document.querySelectorAll('.img_snap')[0]) {document.querySelectorAll('.img_snap')[0].style.display = 'none';} - if (document.querySelector('#display_msg_text')) {document.querySelector('#display_msg_text').style.display = 'none';} - }); - page.evaluate(function() { - var hide = document.querySelectorAll('.gmnoprint'); - for (var index = 0; index < hide.length; ++index) { - hide[index].style.display = 'none'; - } - }); -} - -/** - * Prepare map for screenshooting. Make screenshots same width and height with map_canvas - * If IITC, also set width and height - * @param {boolean} iitcz - * @param {number} widthz - * @param {number} heightz - */ -function prepare(widthz, heightz, search) { - system.stdout.writeLine('prepare...'); - if (search == "nix") { - var selector = "#map_canvas"; - setElementBounds(selector); - }else{ - page.evaluate(function(search) { - if (document.querySelector('#geocode')){ - document.getElementById("address").value=search; - document.querySelector("input[value=Search]").click(); - } - }, search); - var selector = "#map_canvas"; - setElementBounds(selector); - } -} - -/** - * Sets element bounds - * @param selector - */ -function setElementBounds(selector) { - page.clipRect = page.evaluate(function(selector) { - var clipRect = document.querySelector(selector).getBoundingClientRect(); - return { - top: clipRect.top, - left: clipRect.left, - width: clipRect.width, - height: clipRect.height - }; - }, selector); -} - -/** - * Checks if human presence not detected and makes a human present - * @since 2.3.0 - */ -function humanPresence() { - var outside = page.evaluate(function() { - return !!(document.getElementById('butterbar') && (document.getElementById('butterbar').style.display !== 'none')); - }); - if (outside) { - var rekt = page.evaluate(function() { - return document.getElementById('butterbar').getBoundingClientRect(); - }); - page.sendEvent('click', rekt.left + rekt.width / 2, rekt.top + rekt.height / 2); - } -} - -function getDateTime(format) { - var now = new Date(); - var year = now.getFullYear(); - var month = now.getMonth()+1; - var day = now.getDate(); - var hour = now.getHours(); - var minute = now.getMinutes(); - var second = now.getSeconds(); - var timeZone = ''; - if(month.toString().length === 1) { - month = '0' + month; - } - if(day.toString().length === 1) { - day = '0' + day; - } - if(hour.toString().length === 1) { - hour = '0' + hour; - } - if(minute.toString().length === 1) { - minute = '0' + minute; - } - if(second.toString().length === 1) { - second = '0' + second; - } - var dateTime; - if (format === 1) { - dateTime = year + '-' + month + '-' + day + '--' + hour + '-' + minute + '-' + second; - } else { - dateTime = day + '.' + month + '.' + year + ' ' + hour + ':' + minute + ':' + second + timeZone; - } - return dateTime; -} - -function addTimestamp(time) { - page.evaluate(function(dateTime) { - var water = document.createElement('p'); - water.id='watermark-ice'; - water.innerHTML = dateTime; - water.style.position = 'absolute'; - water.style.color = 'orange'; - water.style.top = '0'; - water.style.left = '0'; - water.style.fontSize = '40px'; - water.style.opacity = '0.8'; - water.style.marginTop = '0'; - water.style.paddingTop = '0'; - water.style.fontFamily = 'monospace'; - water.style.textShadow = '2px 2px 5px #111717'; - document.querySelector('#map_canvas').appendChild(water); - }, time); -} - -/** - * Main function. - */ -function main() { - system.stdout.writeLine('main...'); - if (true){ - page.evaluate(function() { - if (document.getElementById('watermark-ice')) { - var oldStamp = document.getElementById('watermark-ice'); - oldStamp.parentNode.removeChild(oldStamp); - } - }); - } - humanPresence(); - window.setTimeout(function() { - addTimestamp(getDateTime(0)); - file = filepath; - s(file); - }, 5000); -} diff --git a/requirements.txt b/requirements.txt @@ -0,0 +1,2 @@ +bs4 +requests diff --git a/screencap_iitc.js b/screencap_iitc.js @@ -0,0 +1,278 @@ +var system = require('system'); +var args = system.args; +var page = require('webpage').create(); +var fs = require('fs'); +if (args.length === 1) { + console.log('Try to pass some args when invoking this script!'); +} else { + if (args.length === 6){ + var SACSID = args[1]; + var CSRF = args[2]; + var IntelURL = args[3]; + var filepath = args[4]; + var plugins_file = args[5]; + var search = 'nix'; + }else{ + if (args.length === 7){ + var SACSID = args[1]; + var CSRF = args[2]; + var IntelURL = args[3]; + var filepath = args[4]; + var search = args[5]; + var plugins_file = args[6]; + } + } +} + +function addCookies(sacsid, csrf) { + phantom.addCookie({ + name: 'SACSID', + value: sacsid, + domain: 'www.ingress.com', + path: '/', + httponly: true, + secure: true + }); + phantom.addCookie({ + name: 'csrftoken', + value: csrf, + domain: 'www.ingress.com', + path: '/' + }); +} + + +function waitFor ($config) { + $config._start = $config._start || new Date(); + if ($config.timeout && new Date - $config._start > $config.timeout) { + if ($config.error) $config.error(); + if ($config.debug) console.log('timedout ' + (new Date - $config._start) + 'ms'); + return; + } + if ($config.check()) { + if ($config.debug) console.log('success ' + (new Date - $config._start) + 'ms'); + return $config.success(); + } + setTimeout(waitFor, $config.interval || 0, $config); +} + +function loadIitcPlugin(src) { + page.evaluate(function(src) { + var script = document.createElement('script'); + script.type='text/javascript'; + script.src=src; + document.head.insertBefore(script, document.head.lastChild); + }, src); +} + +function loadLocalIitcPlugin(src) { + page.injectJs(src) +} + +addCookies(SACSID, CSRF); +afterCookieLogin(IntelURL, search); + +function afterCookieLogin(IntelURL, search) { + page.viewportSize = { width: '1920', height: '1080' }; + page.open(IntelURL, function(status) { + if (status !== 'success') {quit('unable to connect to remote server')} + page.injectJs('https://code.jquery.com/jquery-3.1.1.min.js'); + setTimeout(function() { + page.evaluate(function() { + localStorage['ingress.intelmap.layergroupdisplayed'] = JSON.stringify({ + "Unclaimed Portals":Boolean(1 === 1), + "Level 1 Portals":Boolean(1 === 1), + "Level 2 Portals":Boolean((1 <= 2) && (8 >= 2)), + "Level 3 Portals":Boolean((1 <= 3) && (8 >= 3)), + "Level 4 Portals":Boolean((1 <= 4) && (8 >= 4)), + "Level 5 Portals":Boolean((1 <= 5) && (8 >= 5)), + "Level 6 Portals":Boolean((1 <= 6) && (8 >= 6)), + "Level 7 Portals":Boolean((1 <= 7) && (8 >= 7)), + "Level 8 Portals":Boolean(8 === 8), + "DEBUG Data Tiles":false, + "Artifacts":true, + "Ornaments":true + }); + var script = document.createElement('script'); + script.type='text/javascript'; + script.src='https://secure.jonatkins.com/iitc/release/total-conversion-build.user.js'; + document.head.insertBefore(script, document.head.lastChild); + }); + loadIitcPlugin('http://iitc.jonatkins.com/release/plugins/canvas-render.user.js'); + var plugins = JSON.parse(fs.read(plugins_file)); + for(var i in plugins){ + var plugin = plugins[i]; + if(plugin.match('^[a-zA-Z]+://')){ + loadIitcPlugin(plugin); + }else{ + loadLocalIitcPlugin(plugin); + } + } + setTimeout(function() { + if (search != "nix") { + page.evaluate(function(search) { + if (document.querySelector('#search')){ + window.setTimeout(function() { + document.getElementById("search").value=search; + var e = jQuery.Event("keypress"); + e.which = 13; + e.keyCode = 13; + $("#search").trigger(e); + }, 2000); + var checkExist = setInterval(function() { + if ($('.searchquery').length > 0) { + window.setTimeout(function() {$('.searchquery > :nth-child(2)').children()[0].click();}, 1000); + clearInterval(checkExist); + } + }, 100); + } + }, search); + } + waitFor({ + timeout: 120000, + check: function () { + return page.evaluate(function() { + if (document.querySelector('.map').textContent.indexOf('done') != -1) { + return true; + }else{ + return false; + } + }); + }, + success: function () { + hideDebris(); + prepare('1920', '1080'); + main(); + }, + error: function () { + hideDebris(); + prepare('1920', '1080'); + main(); + } + }); + }, "5000"); + }, "5000"); + }); +} + +function s(file) { + page.render(file); + phantom.exit(0); +} + +function hideDebris() { + window.setTimeout(function() { + page.evaluate(function() { + if (document.querySelector('#chat')) {document.querySelector('#chat').style.display = 'none';} + if (document.querySelector('#chatcontrols')) {document.querySelector('#chatcontrols').style.display = 'none';} + if (document.querySelector('#chatinput')) {document.querySelector('#chatinput').style.display = 'none';} + if (document.querySelector('#updatestatus')) {document.querySelector('#updatestatus').style.display = 'none';} + if (document.querySelector('#sidebartoggle')) {document.querySelector('#sidebartoggle').style.display = 'none';} + if (document.querySelector('#scrollwrapper')) {document.querySelector('#scrollwrapper').style.display = 'none';} + if (document.querySelector('.leaflet-control-container')) {document.querySelector('.leaflet-control-container').style.display = 'none';} + }); + }, 2000); +} + +function prepare(widthz, heightz) { + window.setTimeout(function() { + page.evaluate(function(w, h) { + $("span:contains(' Google Roads')").prev().click(); + var water = document.createElement('p'); + water.id='viewport-ice'; + water.style.position = 'absolute'; + water.style.top = '0'; + water.style.marginTop = '0'; + water.style.paddingTop = '0'; + water.style.left = '0'; + water.style.width = w + 'px'; + water.style.height = h + 'px'; + document.querySelectorAll('body')[0].appendChild(water); + }, widthz, heightz); + var selector = "#viewport-ice"; + setElementBounds(selector); + }, 4000); +} + + +function setElementBounds(selector) { + page.clipRect = page.evaluate(function(selector) { + var clipRect = document.querySelector(selector).getBoundingClientRect(); + return { + top: clipRect.top, + left: clipRect.left, + width: clipRect.width, + height: clipRect.height + }; + }, selector); +} + +function getDateTime(format) { + var now = new Date(); + var year = now.getFullYear(); + var month = now.getMonth()+1; + var day = now.getDate(); + var hour = now.getHours(); + var minute = now.getMinutes(); + var second = now.getSeconds(); + var timeZone = ''; + if(month.toString().length === 1) { + month = '0' + month; + } + if(day.toString().length === 1) { + day = '0' + day; + } + if(hour.toString().length === 1) { + hour = '0' + hour; + } + if(minute.toString().length === 1) { + minute = '0' + minute; + } + if(second.toString().length === 1) { + second = '0' + second; + } + var dateTime; + if (format === 1) { + dateTime = year + '-' + month + '-' + day + '--' + hour + '-' + minute + '-' + second; + } else { + dateTime = day + '.' + month + '.' + year + ' ' + hour + ':' + minute + ':' + second + timeZone; + } + return dateTime; +} + +function addTimestamp(time) { + page.evaluate(function(dateTime) { + var water = document.createElement('p'); + water.id='watermark-ice'; + water.innerHTML = dateTime; + water.style.position = 'absolute'; + water.style.color = '#3A539B'; + water.style.top = '0'; + water.style.zIndex = '4404'; + water.style.marginTop = '0'; + water.style.paddingTop = '0'; + water.style.left = '0'; + water.style.fontSize = '40px'; + water.style.opacity = '0.8'; + water.style.fontFamily = 'monospace'; + water.style.textShadow = 'rgb(3, 3, 3) 7px 5px 9px'; + document.querySelectorAll('body')[0].appendChild(water); + }, time); +} + +/** + * Main function. + */ +function main() { + page.evaluate(function() { + if (document.getElementById('watermark-ice')) { + var oldStamp = document.getElementById('watermark-ice'); + oldStamp.parentNode.removeChild(oldStamp); + } + }); + window.setTimeout(function() { + addTimestamp(getDateTime(0)); + file = filepath; + s(file); + }, 3000); +} diff --git a/screencap_intel.js b/screencap_intel.js @@ -0,0 +1,232 @@ +var system = require('system') +var args = system.args; +var page = require('webpage').create(); +var fs = require('fs'); +if (args.length === 1) { + console.log('Try to pass some args when invoking this script!'); +} else { + if (args.length === 5){ + var SACSID = args[1]; + var CSRF = args[2]; + var IntelURL = args[3]; + var filepath = args[4]; + var search = 'nix'; + }else{ + if (args.length === 6){ + var SACSID = args[1]; + var CSRF = args[2]; + var IntelURL = args[3]; + var filepath = args[4]; + var search = args[5]; + } + } +} + +addCookies(SACSID,CSRF); +afterCookieLogin(IntelURL, search); + +function addCookies(sacsid, csrf) { + phantom.addCookie({ + name: 'SACSID', + value: sacsid, + domain: 'www.ingress.com', + path: '/', + httponly: true, + secure: true + }); + phantom.addCookie({ + name: 'csrftoken', + value: csrf, + domain: 'www.ingress.com', + path: '/' + }); +} + +function waitFor ($config) { + $config._start = $config._start || new Date(); + if ($config.timeout && new Date - $config._start > $config.timeout) { + if ($config.error) $config.error(); + if ($config.debug) console.log('timedout ' + (new Date - $config._start) + 'ms'); + return; + } + if ($config.check()) { + if ($config.debug) console.log('success ' + (new Date - $config._start) + 'ms'); + return $config.success(); + } + setTimeout(waitFor, $config.interval || 0, $config); +} + +function afterCookieLogin(IntelURL, search) { + page.open(IntelURL, function(status) { + if (status !== 'success') {quit('unable to connect to remote server')} + + setTimeout(function() { + waitFor({ + timeout: 120000, + check: function () { + return page.evaluate(function() { + if (document.querySelector('#percent_text').textContent.indexOf('90') != -1) { + if (!document.getElementById("loading_msg").style.display){ + return true; + }else{ + return false; + } + }else{ + return false; + } + }); + }, + success: function () { + page.evaluate(function() { + document.querySelector("#filters_container").style.display= 'none'; + }); + hideDebris(); + prepare('1920', '1080', search); + main(); + }, + error: function () { + page.evaluate(function() { + document.querySelector("#filters_container").style.display= 'none'; + }); + hideDebris(); + prepare('1920', '1080', search); + main(); + } + }); + }, "5000"); + }); +} + +function s(file) { + page.render(file); + phantom.exit(0); +} + +function hideDebris() { + page.evaluate(function() { + if (document.querySelector('#comm')) {document.querySelector('#comm').style.display = 'none';} + if (document.querySelector('#player_stats')) {document.querySelector('#player_stats').style.display = 'none';} + if (document.querySelector('#game_stats')) {document.querySelector('#game_stats').style.display = 'none';} + if (document.querySelector('#geotools')) {document.querySelector('#geotools').style.display = 'none';} + if (document.querySelector('#header')) {document.querySelector('#header').style.display = 'none';} + if (document.querySelector('#snapcontrol')) {document.querySelector('#snapcontrol').style.display = 'none';} + if (document.querySelectorAll('.img_snap')[0]) {document.querySelectorAll('.img_snap')[0].style.display = 'none';} + if (document.querySelector('#display_msg_text')) {document.querySelector('#display_msg_text').style.display = 'none';} + }); + page.evaluate(function() { + var hide = document.querySelectorAll('.gmnoprint'); + for (var index = 0; index < hide.length; ++index) { + hide[index].style.display = 'none'; + } + }); +} + +function prepare(widthz, heightz, search) { + if (search == "nix") { + var selector = "#map_canvas"; + setElementBounds(selector); + }else{ + page.evaluate(function(search) { + if (document.querySelector('#geocode')){ + document.getElementById("address").value=search; + document.querySelector("input[value=Search]").click(); + } + }, search); + var selector = "#map_canvas"; + setElementBounds(selector); + } +} + +function setElementBounds(selector) { + page.clipRect = page.evaluate(function(selector) { + var clipRect = document.querySelector(selector).getBoundingClientRect(); + return { + top: clipRect.top, + left: clipRect.left, + width: clipRect.width, + height: clipRect.height + }; + }, selector); +} + +function humanPresence() { + var outside = page.evaluate(function() { + return !!(document.getElementById('butterbar') && (document.getElementById('butterbar').style.display !== 'none')); + }); + if (outside) { + var rekt = page.evaluate(function() { + return document.getElementById('butterbar').getBoundingClientRect(); + }); + page.sendEvent('click', rekt.left + rekt.width / 2, rekt.top + rekt.height / 2); + } +} + +function getDateTime(format) { + var now = new Date(); + var year = now.getFullYear(); + var month = now.getMonth()+1; + var day = now.getDate(); + var hour = now.getHours(); + var minute = now.getMinutes(); + var second = now.getSeconds(); + var timeZone = ''; + if(month.toString().length === 1) { + month = '0' + month; + } + if(day.toString().length === 1) { + day = '0' + day; + } + if(hour.toString().length === 1) { + hour = '0' + hour; + } + if(minute.toString().length === 1) { + minute = '0' + minute; + } + if(second.toString().length === 1) { + second = '0' + second; + } + var dateTime; + if (format === 1) { + dateTime = year + '-' + month + '-' + day + '--' + hour + '-' + minute + '-' + second; + } else { + dateTime = day + '.' + month + '.' + year + ' ' + hour + ':' + minute + ':' + second + timeZone; + } + return dateTime; +} + +function addTimestamp(time) { + page.evaluate(function(dateTime) { + var water = document.createElement('p'); + water.id='watermark-ice'; + water.innerHTML = dateTime; + water.style.position = 'absolute'; + water.style.color = 'orange'; + water.style.top = '0'; + water.style.left = '0'; + water.style.fontSize = '40px'; + water.style.opacity = '0.8'; + water.style.marginTop = '0'; + water.style.paddingTop = '0'; + water.style.fontFamily = 'monospace'; + water.style.textShadow = '2px 2px 5px #111717'; + document.querySelector('#map_canvas').appendChild(water); + }, time); +} + +/** + * Main function. + */ +function main() { + page.evaluate(function() { + if (document.getElementById('watermark-ice')) { + var oldStamp = document.getElementById('watermark-ice'); + oldStamp.parentNode.removeChild(oldStamp); + } + }); + humanPresence(); + window.setTimeout(function() { + addTimestamp(getDateTime(0)); + file = filepath; + s(file); + }, 5000); +}