// ==UserScript== // @author xificurk // @id uniques-gdpr@xificurk // @name show uniques visit/captures based on GDPR game_log // @category Misc // @version 0.1.0.20201122.121942 // @namespace https://github.com/xificurk/iitc-plugins // @updateURL https://raw.githubusercontent.com/IITC-CE/Community-plugins/master/dist/xificurk/uniques-gdpr.meta.js // @downloadURL https://raw.githubusercontent.com/IITC-CE/Community-plugins/master/dist/xificurk/uniques-gdpr.user.js // @description [xificurk-2020-11-22-121942] Show uniques visit/captures based on GDPR game_log // @issueTracker https://github.com/xificurk/iitc-plugins/issues // @homepageURL https://github.com/xificurk/iitc-plugins // @include https://intel.ingress.com/* // @include http://intel.ingress.com/* // @include https://*.ingress.com/intel* // @include http://*.ingress.com/intel* // @include https://*.ingress.com/mission/* // @include http://*.ingress.com/mission/* // @match https://intel.ingress.com/* // @match http://intel.ingress.com/* // @match https://*.ingress.com/intel* // @match http://*.ingress.com/intel* // @match https://*.ingress.com/mission/* // @match http://*.ingress.com/mission/* // @grant none // ==/UserScript== function wrapper(plugin_info) { // ensure plugin framework is there, even if iitc is not yet loaded if(typeof window.plugin !== 'function') window.plugin = function() {}; //PLUGIN AUTHORS: writing a plugin outside of the IITC build environment? if so, delete these lines!! //(leaving them in place might break the 'About IITC' page or break update checks) plugin_info.buildName = 'xificurk'; plugin_info.dateTimeVersion = '20201122.121942'; plugin_info.pluginId = 'uniques-gdpr'; //END PLUGIN AUTHORS NOTE //PLUGIN START //////////////////////////////////////////////////////// window.plugin.uniquesGdpr = function() { }; window.plugin.uniquesGdpr.UNMATCHED_UNIQUES_LAYER_MIN_ZOOM = 15; window.plugin.uniquesGdpr.getPortalsInView = function() { var portalsInView = {}; var mapBounds = map.getBounds(); $.each(window.portals, function(guid, portal) { if(mapBounds.contains(portal.getLatLng())) { portalsInView[guid] = portal; } }); return portalsInView; }; window.plugin.uniquesGdpr.getTextStatus = function(state) { if(state) { if(state.captured) { return 'CAPTURED'; } if (state.visited) { return 'VISITED'; } } return '-'; }; // Local storage window.plugin.uniquesGdpr.FIELDS = { 'uniques': 'plugin-uniques-gdpr-data' }; window.plugin.uniquesGdpr.uniques = {}; window.plugin.uniquesGdpr.storeLocal = function(name) { var key = window.plugin.uniquesGdpr.FIELDS[name]; if(key === undefined) { return; } var value = plugin.uniquesGdpr[name]; if(typeof value !== 'undefined' && value !== null) { localStorage[key] = JSON.stringify(plugin.uniquesGdpr[name]); } else { localStorage.removeItem(key); } }; window.plugin.uniquesGdpr.loadLocal = function(name) { var key = window.plugin.uniquesGdpr.FIELDS[name]; if(key === undefined) { return; } if(localStorage[key] !== undefined) { plugin.uniquesGdpr[name] = JSON.parse(localStorage[key]); } }; // Game log import window.plugin.uniquesGdpr.import = function() { window.plugin.uniquesGdpr.uniques = {}; var gameLog = $('#uniquesGdprGameLogImport').val().trim().split("\n"); for(var i = 0; i < gameLog.length; i++) { var line = gameLog[i].trim().split("\t"); var point = line[0] + "," + line[1]; window.plugin.uniquesGdpr.uniques[point] = { visited: line[2] === 'CAPTURED' || line[2] === 'VISITED', captured: line[2] === 'CAPTURED', lat: line[0] / 1E6, lon: line[1] / 1E6 }; } window.plugin.uniquesGdpr.storeLocal('uniques'); // Redraw window.changePortalHighlights($('#portal_highlight_select').val()); window.plugin.uniquesGdpr.delayedUpdateUnmatchedUniquesLayer(0.1); window.alert(gameLog.length + " items from game_log imported."); }; window.plugin.uniquesGdpr.openImportDialog = function() { var html = 'Paste the output of geme_log_parser.py:' + ''; window.dialog({ html: html, title: 'Import filtered game_log', buttons: { 'OK': function() { window.plugin.uniquesGdpr.import(); $(this).dialog('close'); } } }); }; // Compare with uniques window.plugin.uniquesGdpr.compareWithUniques = function() { var data = []; $.each(window.plugin.uniquesGdpr.getPortalsInView(), function(guid, portal) { var point = portal.options.data.latE6 + ',' + portal.options.data.lngE6; var gdprStatus = window.plugin.uniquesGdpr.getTextStatus(window.plugin.uniquesGdpr.uniques[point]); var uniqueStatus = window.plugin.uniquesGdpr.getTextStatus(window.plugin.uniques.uniques[guid]); if(uniqueStatus !== gdprStatus) { data.push([uniqueStatus, gdprStatus, guid]); } }); data.sort(); var html = ''; $.each(data, function(i, row) { var uniqueStatus = row[0]; var gdprStatus = row[1]; var guid = row[2]; var portal = window.portals[guid]; var portalLink = $('').text(portal.options.data.title || '[Unknown title]'); html += '' + portalLink.get(0).outerHTML + '' + uniqueStatus + '' + gdprStatus + '' }); html = '' + html + '
PortalUniquesGDPR
'; window.dialog({ html: html, title: 'GDPR data compared to uniques', width: 400 }); }; // Merge with uniques window.plugin.uniquesGdpr.mergeWithUniques = function() { var changes = []; $.each(window.plugin.uniquesGdpr.getPortalsInView(), function(guid, portal) { var point = portal.options.data.latE6 + ',' + portal.options.data.lngE6; var gdprInfo = window.plugin.uniquesGdpr.uniques[point]; if (!gdprInfo || !gdprInfo.visited) { return; } if (!window.plugin.uniques.uniques[guid]) { window.plugin.uniques.uniques[guid] = {visited: false, captured: false}; } var uniqueInfo = window.plugin.uniques.uniques[guid]; if (gdprInfo.captured) { if (uniqueInfo.captured) { return; } changes.push([window.plugin.uniquesGdpr.getTextStatus(uniqueInfo), 'CAPTURED', guid]); window.plugin.uniques.uniques[guid].captured = true; window.plugin.uniques.uniques[guid].visited = true; } else if (!uniqueInfo.visited) { changes.push([window.plugin.uniquesGdpr.getTextStatus(uniqueInfo), 'VISITED', guid]); window.plugin.uniques.uniques[guid].visited = true; } }); changes.sort(); window.plugin.uniques.storeLocal('uniques'); if(window.plugin.sync) { window.plugin.sync.updateMap('uniques', 'uniques', Object.keys(window.plugin.uniques.uniques)); } // Redraw window.changePortalHighlights($('#portal_highlight_select').val()); var html = ''; $.each(changes, function(i, row) { var originalStatus = row[0]; var newStatus = row[1]; var guid = row[2]; var portal = window.portals[guid]; var portalLink = $('
').text(portal.options.data.title || '[Unknown title]'); html += '' + portalLink.get(0).outerHTML + '' + originalStatus + '' + newStatus + '' }); html = '' + html + '
PortalOld statusNew status
'; window.dialog({ html: html, title: 'Performed changes to uniques data', width: 400 }); }; // Menu window.plugin.uniquesGdpr.openMenuDialog = function() { var html = '
'; if(window.plugin.uniques) { html += '
'; html += '
'; } html = '
' + html + '
'; window.dialog({ html: html, title: 'GDPR uniques' }); }; // Highlighter window.plugin.uniquesGdpr.highlighter = { highlight: function(data) { var point = data.portal.options.data.latE6 + ',' + data.portal.options.data.lngE6; var uniqueInfo = window.plugin.uniquesGdpr.uniques[point]; var style = {}; if(uniqueInfo) { if(uniqueInfo.captured) { // captured (and, implied, visited too) - no highlights } else if(uniqueInfo.visited) { style.fillColor = 'yellow'; style.fillOpacity = 0.6; } else { // we have an 'uniqueInfo' entry for the portal, but it's not set visited or captured? // could be used to flag a portal you don't plan to visit, so use a less opaque red style.fillColor = 'red'; style.fillOpacity = 0.5; } } else { // no visit data at all style.fillColor = 'red'; style.fillOpacity = 0.7; } data.portal.setStyle(style); } }; // Unmatched uniques layers window.plugin.uniquesGdpr.getUnmatchedUniqueMarkerStyle = function(layer) { var scale = window.portalMarkerScale(); var options = { fill: false, stroke: true, weight: 3 * Math.sqrt(scale), opacity: 1 }; if(layer === window.plugin.uniquesGdpr.unmatchedCapturedLayer) { options['color'] = 'black'; options['radius'] = 5 * scale; } else { options['color'] = 'fuchsia'; options['radius'] = 7 * scale; } return options; }; window.plugin.uniquesGdpr.getUnmatchedUniques = function(onlyVisited, onlyCaptured) { var result = []; var mapBounds = window.map.getBounds(); for(var point in window.plugin.uniquesGdpr.uniques) { var unique = window.plugin.uniquesGdpr.uniques[point]; if((onlyVisited && unique.captured) || (onlyCaptured && !unique.captured)) { continue; } var position = L.latLng(unique.lat, unique.lon); if(!mapBounds.contains(position)) { continue; } var isMatched = false; for(var guid in window.portals) { var portal = window.portals[guid]; if(point === portal.options.data.latE6 + ',' + portal.options.data.lngE6) { isMatched = true; break; } } if(!isMatched) { result.push(unique); } } return result; }; window.plugin.uniquesGdpr.updateUnmatchedUniquesLayer = function(layer) { // as this is called every time layers are toggled, there's no point in doing it when the layer is off if(!map.hasLayer(layer)) { return; } layer.clearLayers(); if(map.getZoom() < window.plugin.uniquesGdpr.UNMATCHED_UNIQUES_LAYER_MIN_ZOOM) { return; } var markerOptions = window.plugin.uniquesGdpr.getUnmatchedUniqueMarkerStyle(layer); var uniques = window.plugin.uniquesGdpr.getUnmatchedUniques(layer === window.plugin.uniquesGdpr.unmatchedVisitedLayer, layer === window.plugin.uniquesGdpr.unmatchedCapturedLayer); for(var i = 0; i < uniques.length; i++) { var unique = uniques[i]; var position = L.latLng(unique.lat, unique.lon); var marker = L.circleMarker(position, markerOptions); layer.addLayer(marker); } }; window.plugin.uniquesGdpr.delayedUpdateUnmatchedUniquesLayer = function(wait) { if(window.plugin.uniquesGdpr.timer === undefined) { window.plugin.uniquesGdpr.timer = setTimeout(function() { window.plugin.uniquesGdpr.timer = undefined; window.plugin.uniquesGdpr.updateUnmatchedUniquesLayer(window.plugin.uniquesGdpr.unmatchedVisitedLayer); window.plugin.uniquesGdpr.updateUnmatchedUniquesLayer(window.plugin.uniquesGdpr.unmatchedCapturedLayer); }, wait * 1000); } }; var setup = function() { window.plugin.uniquesGdpr.loadLocal('uniques'); window.addPortalHighlighter('Uniques (GDPR)', window.plugin.uniquesGdpr.highlighter); $('#toolbox').append('
Uniques from GDPR'); window.plugin.uniquesGdpr.unmatchedVisitedLayer = L.layerGroup(); window.addLayerGroup('Unmatched visited portals from GDPR', window.plugin.uniquesGdpr.unmatchedVisitedLayer, false); window.plugin.uniquesGdpr.unmatchedCapturedLayer = L.layerGroup(); window.addLayerGroup('Unmatched captured portals from GDPR', window.plugin.uniquesGdpr.unmatchedCapturedLayer, false); window.addHook('mapDataRefreshEnd', function() { window.plugin.uniquesGdpr.delayedUpdateUnmatchedUniquesLayer(0.5); }); window.map.on('overlayadd overlayremove', function() { window.plugin.uniquesGdpr.delayedUpdateUnmatchedUniquesLayer(1.0); }); }; //PLUGIN END ////////////////////////////////////////////////////////// setup.info = plugin_info; //add the script info data to the function as a property if(!window.bootPlugins) window.bootPlugins = []; window.bootPlugins.push(setup); // if IITC has already booted, immediately run the 'setup' function if(window.iitcLoaded && typeof setup === 'function') setup(); } // wrapper end // inject code into site context var script = document.createElement('script'); var info = {}; if (typeof GM_info !== 'undefined' && GM_info && GM_info.script) info.script = { version: GM_info.script.version, name: GM_info.script.name, description: GM_info.script.description }; script.appendChild(document.createTextNode('('+ wrapper +')('+JSON.stringify(info)+');')); (document.body || document.head || document.documentElement).appendChild(script);