Skip to content

Instantly share code, notes, and snippets.

@MTRNord
Last active November 9, 2016 21:22
Show Gist options
  • Select an option

  • Save MTRNord/4ccb3c4943f71cd28aa9f033ff2e1258 to your computer and use it in GitHub Desktop.

Select an option

Save MTRNord/4ccb3c4943f71cd28aa9f033ff2e1258 to your computer and use it in GitHub Desktop.
Ingress Intel Screenbot
import asyncio, io, logging, os, re, time, tempfile
import subprocess
import plugins
import re
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 _screencap(url, filename, SACSID, CSRF, search):
logger.info("screencapping {} and saving as {}".format(url, filename))
#os.path.realpath(__file__)
if search == False:
command = "phantomjs hangupsbot/plugins/intel_screenbot/screencap.js '" + SACSID + "' '" + CSRF + "' '" + url + "' '" + filename + "'"
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
else:
command = "phantomjs hangupsbot/plugins/intel_screenbot/screencap.js '" + SACSID + "' '" + CSRF + "' '" + url + "' '" + filename + "' '" + search + "'"
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
# make sure phantomjs has time to download/process the page
# but if we get nothing after 30 sec, just move on
try:
output, errors = process.communicate(timeout=30)
except Exception as e:
logger.debug("Exception: {}".format(e))
process.kill()
yield from asyncio.sleep(5)
loop = asyncio.get_event_loop()
# read the resulting file into a byte array
file_resource = yield from _open_file(filename)
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)
# yield from loop.run_in_executor(None, os.remove, filename)
return image_data
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, SACSID, CSRF, search)
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
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))

Ingress Intel Screenbot

Note: Most of the Code in screencap.js comes from ingress-ice which isn't made by me. So code Credits of it goes in the most parts to nibogd. I only modified it for the Bot.

Requires: PhantomJS (installation instructions below) Requires: hangoutsbot

Get and post a screenshot of the Intel Map.

Install

To install the plugin you need to add the __init__.py and screencap.js into a subdirectory named intel_screenbot inside the plugin folder of your bot. Than you need to follow the Configuration part.

Configuration

For using the Intel Screenbot you need to add the following to the config.json:

 "intel_screenbot": {
    "SACSID": "YOUR SACSID",
    "CSRF": "YOUR CSRF"
  }

According to the official INSTALL Documention of the hangoutbot you will find the config.json in /<username>/.local/share/hangupsbot/ (NOTE! add an comma behind the last element of the config.json and add it befor the outer element closes)

Also you need to add intel_screenbot to the plugins.

How to get SACSID and CSRF

You should look at the Documentation of ingress-ice

Admin Commands

/bot setintel <url>

  • Sets the default Intel URL of a particular hangout.

/bot clearintel

  • Clears the default screenshot URL of a particular hangout.

User Command

/bot intel [<url>]

  • 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

Debian-based distros (e.g. Ubuntu 14.04)

sudo apt-get install phantomjs

Building PhantomJS from Source (Advanced)

Note: It is not within the scope of this project to discuss and resolve build problems with external libraries.

Install dependencies

On Debian-based distro (tested on Ubuntu 14.04), run:

sudo apt-get install build-essential g++ flex bison gperf ruby perl \
  libsqlite3-dev libfontconfig1-dev libicu-dev libfreetype6 libssl-dev \
  libpng-dev libjpeg-dev

On Fedora-based distro (tested on CentOS 6), run:

sudo yum -y install gcc gcc-c++ make flex bison gperf ruby \  
  openssl-devel freetype-devel fontconfig-devel libicu-devel sqlite-devel \  
  libpng-devel libjpeg-devel

Install PhantomJS from source

git clone git://github.com/ariya/phantomjs.git
cd phantomjs
git checkout 2.0
./build.sh
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)
}
}
}
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: '/'
});
}
/**
* 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() {
page.evaluate(function() {
document.querySelector("#filters_container").style.display= 'none';
});
hideDebris();
prepare('1920', '1080', search);
main();
}, "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);
}
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';
}
});
}
/**
* 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) {
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() {
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);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment