├── ESIWalletPull.gs ├── EveCentralPrices.gs ├── FuzzworkMarket.gs ├── FuzzworkMarketPrices-Menu.gs ├── HistoryGrabber.gs ├── IndustryJobs.gs ├── LICENSE ├── LoadIndexes.gs ├── MarketOrders.gs ├── OutpostLoader.gs ├── README.md ├── assetloader.gs ├── blueprints.gs ├── citadelmarket.gs ├── esi-nameloader.gs ├── industryFigures.gs ├── kills.gs ├── moons ├── FormSubmissionVersion.gs ├── code.gs └── input.html └── sheetLoader.gs /ESIWalletPull.gs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This is one of the more complex ones to set up. 4 | 5 | I'll probably write up something specific for it at some point, but the blog below covers much of what is needed. 6 | 7 | https://www.fuzzwork.co.uk/2017/03/14/using-esi-google-sheets/ 8 | 9 | you'll need a workbook with 4 sheets. 10 | journal 11 | transactions 12 | typeids 13 | config 14 | corpjournal 15 | corptransactions 16 | 17 | Journal and transactions should be either empty, or with a header row. 18 | 19 | typeids should have a list of the typeids for market types, in the form typeid, name,typeid. The easy way to do this is just stick 20 | =IMPORTDATA("https://www.fuzzwork.co.uk/market/marketitems.csv") in A1 21 | 22 | 23 | Config should be set up as per the blog post (with the named ranges and so on). The refresh token will need to be set up for the character wallet scope and corp wallet scope if you're using that bit 24 | 25 | Once that's all done, you can add the code below to the script editor, 26 | edit the two character ids (CHARACTERIDGOESHERE) to be the right character, edit the two corpids if you'll be using them; then reopen the sheet. 27 | It should have a new API menu item which has an update wallet bit. new entries go to the bottom (but you can sort at will) 28 | 29 | */ 30 | var typeidArray = new Array(); 31 | 32 | function onOpen() { 33 | var ui = SpreadsheetApp.getUi(); 34 | ui.createMenu('API') 35 | .addItem('Update Wallet', 'updateWallet') 36 | .addItem('Update Corp Wallet', 'updateCorpWallet') 37 | .addItem('Get Maxes', 'getMax') 38 | .addItem('Clear Maxes', 'clearMax') 39 | .addToUi(); 40 | } 41 | 42 | function getSetup() { 43 | var config={}; 44 | var namedRanges = SpreadsheetApp.getActiveSpreadsheet().getNamedRanges(); 45 | for (var i = 0; i < namedRanges.length; i++) { 46 | switch (namedRanges[i].getName()) { 47 | case 'clientid': 48 | config.clientid=namedRanges[i].getRange().getCell(1, 1).getValue() ; 49 | break; 50 | case 'secret': 51 | config.secret=namedRanges[i].getRange().getCell(1, 1).getValue() ; 52 | break; 53 | case 'refresh': 54 | config.refreshtoken=namedRanges[i].getRange().getCell(1, 1).getValue() ; 55 | break; 56 | } 57 | 58 | } 59 | var documentProperties = PropertiesService.getDocumentProperties(); 60 | config.expires = documentProperties.getProperty('oauth_expires'); 61 | config.access_token = documentProperties.getProperty('access_token') 62 | config.maxtransactionid=documentProperties.getProperty('maxtransactionid') 63 | config.maxjournalid=documentProperties.getProperty('maxjournalid') 64 | config.maxcorpjournalid=documentProperties.getProperty('maxcorpjournalid') 65 | config.maxcorptransactionid=documentProperties.getProperty('maxcorptransactionid') 66 | return config; 67 | } 68 | 69 | function getMax() { 70 | var documentProperties = PropertiesService.getDocumentProperties(); 71 | maxid=documentProperties.getProperty('maxtransactionid'); 72 | SpreadsheetApp.getUi().alert('max transaction id is:'+maxid); 73 | maxid=documentProperties.getProperty('maxjournalid'); 74 | SpreadsheetApp.getUi().alert('max journal id is:'+maxid); 75 | maxid=documentProperties.getProperty('maxcorpjournalid'); 76 | SpreadsheetApp.getUi().alert('max corp journal id is:'+maxid); 77 | } 78 | 79 | function clearMax() { 80 | var documentProperties = PropertiesService.getDocumentProperties(); 81 | documentProperties.setProperty('maxtransatcionid',0); 82 | } 83 | 84 | function getAccessToken(config) { 85 | 86 | if (Date.now()>config.expires) { 87 | 88 | var url = 'https://login.eveonline.com/oauth/token?' 89 | + 'grant_type=refresh_token' 90 | + '&refresh_token='+config.refreshtoken; 91 | 92 | var code=Utilities.base64Encode(config.clientid+':'+config.secret); 93 | 94 | var headers = { 95 | 'Authorization': 'Basic '+code, 96 | 'Content-Type': 'application/x-www-form-urlencoded', 97 | }; 98 | var parameters = { 99 | 'method': 'post', 100 | 'headers': headers, 101 | }; 102 | var response = UrlFetchApp.fetch(url, parameters).getContentText(); 103 | var json = JSON.parse(response); 104 | var access_token = json['access_token']; 105 | 106 | config.access_token=access_token; 107 | config.expires=Date.now()+1200000 108 | var documentProperties = PropertiesService.getDocumentProperties(); 109 | documentProperties.setProperty('access_token',access_token) 110 | documentProperties.setProperty('oauth_expires',config.expires) 111 | 112 | 113 | } 114 | 115 | return config; 116 | 117 | } 118 | 119 | 120 | 121 | function updateWallet() { 122 | 123 | var config=getSetup(); 124 | 125 | config=getAccessToken(config); 126 | 127 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 128 | 129 | var transactionsheet=ss.getSheetByName("transactions") 130 | var journalsheet=ss.getSheetByName("journal") 131 | var typessheet=ss.getSheetByName("typeids") 132 | 133 | var typeids = typessheet.getDataRange().getValues(); 134 | for (var i = 0; i < typeids.length; i++) { 135 | var key = typeids[i][0]; 136 | typeidArray[key] = typeids[i][1]; 137 | } 138 | 139 | var url = 'https://esi.evetech.net/latest/characters/CHARACTERIDGOESHERE/wallet/transactions/?datasource=tranquility'; 140 | 141 | //transactions 142 | 143 | var parameters = {method : "get", headers : {'Authorization':'Bearer '+ config.access_token,'X-User-Agent':'Steve Ronuken Wallet Updater'}}; 144 | newmax=0; 145 | var jsonFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 146 | var json = JSON.parse(jsonFeed); 147 | if(json) { 148 | for(i in json) { 149 | if (parseInt(json[i].transaction_id)>config.maxtransactionid) { 150 | transactionsheet.appendRow( 151 | [json[i].transaction_id, 152 | json[i].date, 153 | json[i].location_id, 154 | json[i].type_id, 155 | typeidArray[parseInt(json[i].type_id)], 156 | json[i].unit_price, 157 | json[i].quantity, 158 | json[i].client_id, 159 | json[i].is_buy, 160 | json[i].is_personal, 161 | json[i].journal_ref_id] 162 | ); 163 | if (parseInt(json[i].transaction_id)>newmax){ 164 | newmax=parseInt(json[i].transaction_id); 165 | } 166 | } 167 | } 168 | if (newmax>config.maxtransactionid) { 169 | var documentProperties = PropertiesService.getDocumentProperties(); 170 | documentProperties.setProperty('maxtransactionid',newmax) 171 | } 172 | } 173 | 174 | 175 | var url = 'https://esi.evetech.net/latest/characters/CHARACTERIDGOESHERE/wallet/journal/?datasource=tranquility'; 176 | newmax=0; 177 | var jsonFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 178 | var json = JSON.parse(jsonFeed); 179 | if(json) { 180 | for(i in json) { 181 | if (parseInt(json[i].ref_id)>config.maxjournalid) { 182 | transaction=[ 183 | json[i].ref_id, 184 | json[i].ref_type, 185 | json[i].date, 186 | json[i].first_party_id, 187 | json[i].first_party_type, 188 | json[i].second_party_id, 189 | json[i].second_party_type, 190 | json[i].amount, 191 | json[i].balance, 192 | json[i].reason 193 | ]; 194 | if (json[i].extra_info!=null) { 195 | transaction.push(json[i].extra_info.transaction_id) 196 | transaction.push(json[i].extra_info.system_id) 197 | transaction.push(json[i].extra_info.character_id) 198 | if (json[i].extra_info.transaction_id!=null) { 199 | transaction.push("=vlookup("+json[i].extra_info.transaction_id+",transactions!A:G,5,false)") 200 | } 201 | } 202 | journalsheet.appendRow(transaction) 203 | if (parseInt(json[i].ref_id)>newmax){ 204 | newmax=parseInt(json[i].ref_id); 205 | } 206 | } 207 | } 208 | if (newmax>config.maxjournalid) { 209 | var documentProperties = PropertiesService.getDocumentProperties(); 210 | documentProperties.setProperty('maxjournalid',newmax) 211 | } 212 | } 213 | } 214 | 215 | function updateCorpWallet() { 216 | 217 | var config=getSetup(); 218 | 219 | config=getAccessToken(config); 220 | 221 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 222 | 223 | var transactionsheet=ss.getSheetByName("corptransactions") 224 | var journalsheet=ss.getSheetByName("corpjournal") 225 | var typessheet=ss.getSheetByName("typeids") 226 | 227 | var typeids = typessheet.getDataRange().getValues(); 228 | for (var i = 0; i < typeids.length; i++) { 229 | var key = typeids[i][0]; 230 | typeidArray[key] = typeids[i][1]; 231 | } 232 | var parameters = {method : "get", headers : {'Authorization':'Bearer '+ config.access_token,'X-User-Agent':'Steve Ronuken Wallet Updater'}}; 233 | 234 | var url = 'https://esi.evetech.net/latest/corporations/CORPIDGOESHERE/wallets/1/transactions/?datasource=tranquility'; 235 | 236 | //transactions 237 | 238 | 239 | newmax=0; 240 | var jsonFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 241 | var json = JSON.parse(jsonFeed); 242 | if(json) { 243 | for(i in json) { 244 | if (parseInt(json[i].transaction_id)>config.maxcorptransactionid) { 245 | transactionsheet.appendRow( 246 | [json[i].transaction_id, 247 | json[i].date, 248 | json[i].location_id, 249 | json[i].type_id, 250 | typeidArray[parseInt(json[i].type_id)], 251 | json[i].unit_price, 252 | json[i].quantity, 253 | json[i].client_id, 254 | json[i].is_buy, 255 | json[i].journal_ref_id] 256 | ); 257 | if (parseInt(json[i].transaction_id)>newmax){ 258 | newmax=parseInt(json[i].transaction_id); 259 | } 260 | } 261 | } 262 | if (newmax>config.maxcorptransactionid) { 263 | var documentProperties = PropertiesService.getDocumentProperties(); 264 | documentProperties.setProperty('maxcorptransactionid',newmax) 265 | } 266 | } 267 | 268 | url = 'https://esi.evetech.net/latest/corporations/CORPIDGOESHERE/wallets/1/journal/?datasource=tranquility'; 269 | newmax=0; 270 | var jsonFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 271 | var json = JSON.parse(jsonFeed); 272 | if(json) { 273 | for(i in json) { 274 | if (parseInt(json[i].ref_id)>config.maxcorpjournalid) { 275 | transaction=[ 276 | json[i].ref_id, 277 | json[i].ref_type, 278 | json[i].date, 279 | json[i].first_party_id, 280 | json[i].first_party_type, 281 | json[i].second_party_id, 282 | json[i].second_party_type, 283 | json[i].amount, 284 | json[i].balance, 285 | json[i].reason 286 | ]; 287 | if (json[i].extra_info!=null) { 288 | transaction.push(json[i].extra_info.transaction_id) 289 | transaction.push(json[i].extra_info.system_id) 290 | transaction.push(json[i].extra_info.character_id) 291 | if (json[i].extra_info.transaction_id!=null) { 292 | transaction.push("=vlookup("+json[i].extra_info.transaction_id+",transactions!A:G,5,false)") 293 | } 294 | } 295 | journalsheet.appendRow(transaction) 296 | if (parseInt(json[i].ref_id)>newmax){ 297 | newmax=parseInt(json[i].ref_id); 298 | } 299 | } 300 | } 301 | if (newmax>config.maxcorpjournalid) { 302 | var documentProperties = PropertiesService.getDocumentProperties(); 303 | documentProperties.setProperty('maxcorpjournalid',newmax) 304 | } 305 | } 306 | } 307 | -------------------------------------------------------------------------------- /EveCentralPrices.gs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Takes a bunch of typeids from a list (duplicates are fine. multidimensional is fine) and returns a bunch of rows 4 | with relevant price data. 5 | 6 | TypeID,Buy Volume,Buy average,Buy max,Buy min,Buy Std deviation,Buy median,Buy Percentile, 7 | Sell Volume,Sell Average,Sell Max,Sell Min,Sell std Deviation,Sell Median,sell Percentile 8 | 9 | 10 | 11 | I'd suggest loading price data into a new sheet, then using vlookup to get the bits you care about in your main sheet. 12 | 13 | loadRegionPrices defaults to the Forge 14 | loadSystemPrices defaults to Jita 15 | 16 | 17 | =loadRegionPrices(A1:A28) 18 | =loadRegionPrices(A1:A28,10000002) 19 | =loadRegionPrices(A1:A28,10000002,47) 20 | 21 | =loadSystemPrices(A1:A28) 22 | 23 | 24 | 25 | 26 | 27 | 28 | An example below: 29 | 30 | https://docs.google.com/spreadsheets/d/1f9-4cb4Tx64Do-xmHhELSwZGahZ2mTTkV7mKDBRPrrY/edit?usp=sharing 31 | 32 | */ 33 | /* 34 | * Loads prices for a given set of typeIDs for a specific region using Eve-Central's data. 35 | * @param priceIDs A range where the item typeIDs are found. 36 | * @param regionID The region to query. 37 | * @param {number} cachebuster Increment this variable to refresh the data. 38 | * @return The price data in multiple columns in the following order: TypeID,Buy Volume,Buy average,Buy max,Buy min,Buy Std deviation,Buy median,Buy Percentile,Sell Volume,Sell Average,Sell Max,Sell Min,Sell std Deviation,Sell Median,sell Percentile. This is suitable for use with VLOOKUP. 39 | * @customfunction 40 | */ 41 | function loadRegionPrices(priceIDs,regionID,cachebuster){ 42 | if (typeof regionID == 'undefined'){ 43 | regionID=10000002; 44 | } 45 | if (typeof priceIDs == 'undefined'){ 46 | throw 'need typeids'; 47 | } 48 | if (typeof cachebuster == 'undefined'){ 49 | cachebuster=1; 50 | } 51 | var prices = new Array(); 52 | var dirtyTypeIds = new Array(); 53 | var cleanTypeIds = new Array(); 54 | var url="http://api.eve-central.com/api/marketstat?cachebuster="+cachebuster+"®ionlimit="+regionID+"&typeid="; 55 | priceIDs.forEach (function (row) { 56 | row.forEach ( function (cell) { 57 | if (typeof(cell) === 'number' ) { 58 | dirtyTypeIds.push(cell); 59 | } 60 | }); 61 | }); 62 | cleanTypeIds = dirtyTypeIds.filter(function(v,i,a) { 63 | return a.indexOf(v)===i; 64 | }); 65 | var parameters = {method : "get", payload : ""}; 66 | 67 | var o,j,temparray,chunk = 100; 68 | for (o=0,j=cleanTypeIds.length; o < j; o+=chunk) { 69 | temparray = cleanTypeIds.slice(o,o+chunk); 70 | Utilities.sleep(100); 71 | var xmlFeed = UrlFetchApp.fetch(url+temparray.join("&typeid="), parameters).getContentText(); 72 | var xml = XmlService.parse(xmlFeed); 73 | if(xml) { 74 | var rows=xml.getRootElement().getChild("marketstat").getChildren("type"); 75 | for(var i = 0; i < rows.length; i++) { 76 | var price=[parseInt(rows[i].getAttribute("id").getValue()), 77 | parseInt(rows[i].getChild("buy").getChild("volume").getValue()), 78 | parseFloat(rows[i].getChild("buy").getChild("avg").getValue()), 79 | parseFloat(rows[i].getChild("buy").getChild("max").getValue()), 80 | parseFloat(rows[i].getChild("buy").getChild("min").getValue()), 81 | parseFloat(rows[i].getChild("buy").getChild("stddev").getValue()), 82 | parseFloat(rows[i].getChild("buy").getChild("median").getValue()), 83 | parseFloat(rows[i].getChild("buy").getChild("percentile").getValue()), 84 | parseInt(rows[i].getChild("sell").getChild("volume").getValue()), 85 | parseFloat(rows[i].getChild("sell").getChild("avg").getValue()), 86 | parseFloat(rows[i].getChild("sell").getChild("max").getValue()), 87 | parseFloat(rows[i].getChild("sell").getChild("min").getValue()), 88 | parseFloat(rows[i].getChild("sell").getChild("stddev").getValue()), 89 | parseFloat(rows[i].getChild("sell").getChild("median").getValue()), 90 | parseFloat(rows[i].getChild("sell").getChild("percentile").getValue())]; 91 | prices.push(price); 92 | } 93 | } 94 | } 95 | return prices; 96 | } 97 | 98 | /* 99 | * Loads prices for a given set of typeIDs for a specific region using Eve-Central's data. 100 | * @param priceIDs A range where the item typeIDs are found. 101 | * @param systemID The system to query. 102 | * @param {number} cachebuster Increment this variable to refresh the data. 103 | * @return The price data in multiple columns in the following order: TypeID,Buy Volume,Buy average,Buy max,Buy min,Buy Std deviation,Buy median,Buy Percentile,Sell Volume,Sell Average,Sell Max,Sell Min,Sell std Deviation,Sell Median,sell Percentile. This is suitable for use with VLOOKUP. 104 | * @customfunction 105 | */ 106 | function loadSystemPrices(priceIDs,systemID,cachebuster){ 107 | if (typeof systemID == 'undefined'){ 108 | systemID=30000142; 109 | } 110 | if (typeof priceIDs == 'undefined'){ 111 | throw 'need typeids'; 112 | } 113 | if (typeof cachebuster == 'undefined'){ 114 | cachebuster=1; 115 | } 116 | var prices = new Array(); 117 | var dirtyTypeIds = new Array(); 118 | var cleanTypeIds = new Array(); 119 | var url="http://api.eve-central.com/api/marketstat?cachebuster="+cachebuster+"&usesystem="+systemID+"&typeid="; 120 | priceIDs.forEach (function (row) { 121 | row.forEach ( function (cell) { 122 | if (typeof(cell) === 'number' ) { 123 | dirtyTypeIds.push(cell); 124 | } 125 | }); 126 | }); 127 | cleanTypeIds = dirtyTypeIds.filter(function(v,i,a) { 128 | return a.indexOf(v)===i; 129 | }); 130 | var parameters = {method : "get", payload : ""}; 131 | 132 | var o,j,temparray,chunk = 100; 133 | for (o=0,j=cleanTypeIds.length; o < j; o+=chunk) { 134 | temparray = cleanTypeIds.slice(o,o+chunk); 135 | var xmlFeed = UrlFetchApp.fetch(url+temparray.join("&typeid="), parameters).getContentText(); 136 | var xml = XmlService.parse(xmlFeed); 137 | if(xml) { 138 | var rows=xml.getRootElement().getChild("marketstat").getChildren("type"); 139 | for(var i = 0; i < rows.length; i++) { 140 | var price=[parseInt(rows[i].getAttribute("id").getValue()), 141 | parseInt(rows[i].getChild("buy").getChild("volume").getValue()), 142 | parseFloat(rows[i].getChild("buy").getChild("avg").getValue()), 143 | parseFloat(rows[i].getChild("buy").getChild("max").getValue()), 144 | parseFloat(rows[i].getChild("buy").getChild("min").getValue()), 145 | parseFloat(rows[i].getChild("buy").getChild("stddev").getValue()), 146 | parseFloat(rows[i].getChild("buy").getChild("median").getValue()), 147 | parseFloat(rows[i].getChild("buy").getChild("percentile").getValue()), 148 | parseInt(rows[i].getChild("sell").getChild("volume").getValue()), 149 | parseFloat(rows[i].getChild("sell").getChild("avg").getValue()), 150 | parseFloat(rows[i].getChild("sell").getChild("max").getValue()), 151 | parseFloat(rows[i].getChild("sell").getChild("min").getValue()), 152 | parseFloat(rows[i].getChild("sell").getChild("stddev").getValue()), 153 | parseFloat(rows[i].getChild("sell").getChild("median").getValue()), 154 | parseFloat(rows[i].getChild("sell").getChild("percentile").getValue())]; 155 | prices.push(price); 156 | } 157 | } 158 | } 159 | return prices; 160 | } 161 | -------------------------------------------------------------------------------- /FuzzworkMarket.gs: -------------------------------------------------------------------------------- 1 | // Requires a list of typeids, so something like Types!A:A 2 | // https://docs.google.com/spreadsheets/d/1IixV0eNqg19FE6cLzb83G1Ucb0Otl-Jnvm6csAlPKwo/edit?usp=sharing for an example 3 | 4 | function loadRegionAggregates(priceIDs,regionID){ 5 | if (typeof regionID == 'undefined'){ 6 | regionID=10000002; 7 | } 8 | if (typeof priceIDs == 'undefined'){ 9 | throw 'Need a list of typeids'; 10 | } 11 | 12 | var prices = new Array(); 13 | var dirtyTypeIds = new Array(); 14 | var cleanTypeIds = new Array(); 15 | var url="https://market.fuzzwork.co.uk/aggregates/?region="+regionID+"&types=" 16 | 17 | priceIDs.forEach (function (row) { 18 | row.forEach ( function (cell) { 19 | if (typeof(cell) === 'number' ) { 20 | dirtyTypeIds.push(cell); 21 | } 22 | }); 23 | }); 24 | cleanTypeIds = dirtyTypeIds.filter(function(v,i,a) { 25 | return a.indexOf(v)===i; 26 | }); 27 | prices.push(['TypeID','Buy volume','Buy Weighted Average','Max Buy','Min Buy','Buy Std Dev','Median Buy','Percentile Buy Price','Sell volume','Sell Weighted Average','Max sell','Min Sell','Sell Std Dev','Median Sell','Percentile Sell Price']) 28 | var parameters = {method : "get", payload : ""}; 29 | 30 | var o,j,temparray,chunk = 100; 31 | for (o=0,j=cleanTypeIds.length; o < j; o+=chunk) { 32 | temparray = cleanTypeIds.slice(o,o+chunk); 33 | Utilities.sleep(100); 34 | var types=temparray.join(",").replace(/,$/,'') 35 | var jsonFeed = UrlFetchApp.fetch(url+types, parameters).getContentText(); 36 | var json = JSON.parse(jsonFeed); 37 | if(json) { 38 | for(i in json) { 39 | var price=[parseInt(i), 40 | parseInt(json[i].buy.volume), 41 | parseInt(json[i].buy.weightedAverage), 42 | parseFloat(json[i].buy.max), 43 | parseFloat(json[i].buy.min), 44 | parseFloat(json[i].buy.stddev), 45 | parseFloat(json[i].buy.median), 46 | parseFloat(json[i].buy.percentile), 47 | parseInt(json[i].sell.volume), 48 | parseFloat(json[i].sell.weightedAverage), 49 | parseFloat(json[i].sell.max), 50 | parseFloat(json[i].sell.min), 51 | parseFloat(json[i].sell.stddev), 52 | parseFloat(json[i].sell.median), 53 | parseFloat(json[i].sell.percentile)]; 54 | prices.push(price); 55 | } 56 | } 57 | } 58 | return prices; 59 | } 60 | -------------------------------------------------------------------------------- /FuzzworkMarketPrices-Menu.gs: -------------------------------------------------------------------------------- 1 | // This code depends on having two sheets. One called prices, one called typeids. 2 | // Do not store _anything_ you care about on prices, as it will be wiped each time the function runs. 3 | // Typeids has a single column, with the regionid you want to retrieve at the top, then followed by the typeids. 4 | 5 | // https://docs.google.com/spreadsheets/d/12eBW3OmmyrpYBTdc2NzAjtn0vPDlUr8pCVMcF3PLMIk/edit?usp=sharing for an example 6 | 7 | 8 | // This adds a new menu to the sheet, with a single entry to update prices. 9 | function onOpen() { 10 | var ui = SpreadsheetApp.getUi(); 11 | ui.createMenu('API') 12 | .addItem('Update Prices', 'updatePrices') 13 | .addToUi(); 14 | } 15 | 16 | 17 | function updatePrices(){ 18 | 19 | 20 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 21 | 22 | var resultsheet=ss.getSheetByName("prices") 23 | var typessheet=ss.getSheetByName("typeids") 24 | 25 | var regionID = typessheet.getRange("A1").getValues()[0,0]; 26 | 27 | //clear out the old prices 28 | resultsheet.clear(); 29 | 30 | 31 | 32 | 33 | var prices = new Array(); 34 | var dirtyTypeIds = new Array(); 35 | var cleanTypeIds = new Array(); 36 | var url="https://market.fuzzwork.co.uk/aggregates/?region="+regionID+"&types=" 37 | 38 | 39 | // fill in all the typeids to lookup. 40 | var len = typessheet.getLastRow() 41 | for(var i = 2 ; i < len +1 ; i++){ 42 | var typeid = typessheet.getRange("A"+i).getValue(); 43 | if (typeof(typeid) === 'number' ) { 44 | dirtyTypeIds.push(typeid); 45 | } 46 | } 47 | 48 | // Deduplicate the list 49 | cleanTypeIds = dirtyTypeIds.filter(function(v,i,a) { 50 | return a.indexOf(v)===i; 51 | }); 52 | 53 | // add a header row 54 | resultsheet.appendRow(['TypeID','Buy volume','Buy Weighted Average','Max Buy','Min Buy','Buy Std Dev','Median Buy','Percentile Buy Price','Sell volume','Sell Weighted Average','Max sell','Min Sell','Sell Std Dev','Median Sell','Percentile Sell Price']) 55 | var parameters = {method : "get", payload : ""}; 56 | 57 | 58 | // go through the typeids, 100 at a time. 59 | var o,j,temparray,chunk = 100; 60 | for (o=0,j=cleanTypeIds.length; o < j; o+=chunk) { 61 | temparray = cleanTypeIds.slice(o,o+chunk); 62 | Utilities.sleep(100); 63 | var types=temparray.join(",").replace(/,$/,'') 64 | var jsonFeed = UrlFetchApp.fetch(url+types, parameters).getContentText(); 65 | var json = JSON.parse(jsonFeed); 66 | if(json) { 67 | for(i in json) { 68 | // Add each result to the sheet. 69 | resultsheet.appendRow([parseInt(i), 70 | parseInt(json[i].buy.volume), 71 | parseInt(json[i].buy.weightedAverage), 72 | parseFloat(json[i].buy.max), 73 | parseFloat(json[i].buy.min), 74 | parseFloat(json[i].buy.stddev), 75 | parseFloat(json[i].buy.median), 76 | parseFloat(json[i].buy.percentile), 77 | parseInt(json[i].sell.volume), 78 | parseFloat(json[i].sell.weightedAverage), 79 | parseFloat(json[i].sell.max), 80 | parseFloat(json[i].sell.min), 81 | parseFloat(json[i].sell.stddev), 82 | parseFloat(json[i].sell.median), 83 | parseFloat(json[i].sell.percentile)]); 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /HistoryGrabber.gs: -------------------------------------------------------------------------------- 1 | function loadAllVolumes(typeID,regionID){ 2 | if (typeof regionID == 'undefined'){ 3 | regionID=10000002; 4 | } 5 | if (typeof typeID == 'undefined'){ 6 | throw 'need typeid'; 7 | } 8 | 9 | var prices = new Array(); 10 | var url="https://crest-tq.eveonline.com/market/"+regionID+"/history/?type=https://crest-tq.eveonline.com/inventory/types/"+typeID+"/"; 11 | 12 | var parameters = {method : "get", payload : ""}; 13 | var jsonFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 14 | data = JSON.parse(jsonFeed) 15 | var volumes = new Array(); 16 | 17 | if (data) { 18 | for (var i = 0; i < data.items.length; i++) { 19 | volumes.push(data.items[i].volume); 20 | } 21 | } 22 | 23 | return volumes; 24 | } 25 | 26 | 27 | function zeroFill( number, width ) 28 | { 29 | width -= number.toString().length; 30 | if ( width > 0 ) 31 | { 32 | return new Array( width + (/\./.test( number ) ? 2 : 1) ).join( '0' ) + number; 33 | } 34 | return number + ""; // always return a string 35 | } 36 | 37 | 38 | function loadVolume(typeID,regionID){ 39 | if (typeof regionID == 'undefined'){ 40 | regionID=10000002; 41 | } 42 | if (typeof typeID == 'undefined'){ 43 | throw 'need typeid'; 44 | } 45 | 46 | var prices = new Array(); 47 | var url="https://crest-tq.eveonline.com/market/"+regionID+"/history/?type=https://crest-tq.eveonline.com/inventory/types/"+typeID+"/"; 48 | 49 | var parameters = {method : "get", payload : ""}; 50 | var jsonFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 51 | var volumes = new Array(); 52 | 53 | data = JSON.parse(jsonFeed) 54 | var d = new Date(); 55 | d.setDate(d.getDate() - 1); 56 | month=d.getMonth()+1; 57 | yesterday=d.getFullYear()+"-"+zeroFill(month,2)+"-"+zeroFill(d.getDate(),2)+"T00:00:00"; 58 | 59 | if (data) { 60 | for (var i = 0; i < data.items.length; i++) { 61 | if (data.items[i].date == yesterday) { 62 | volumes.push(data.items[i].volume); 63 | } 64 | } 65 | } 66 | 67 | return volumes; 68 | } 69 | 70 | 71 | 72 | function loadThirtyDayVolume(typeID,regionID){ 73 | if (typeof regionID == 'undefined'){ 74 | regionID=10000002; 75 | } 76 | if (typeof typeID == 'undefined'){ 77 | throw 'need typeid'; 78 | } 79 | 80 | var prices = new Array(); 81 | var url="https://crest-tq.eveonline.com/market/"+regionID+"/history/?type=https://crest-tq.eveonline.com/inventory/types/"+typeID+"/"; 82 | 83 | var parameters = {method : "get", payload : ""}; 84 | var jsonFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 85 | var volumes = new Array(); 86 | 87 | data = JSON.parse(jsonFeed) 88 | var d = new Date(); 89 | time=Date.UTC(d.getFullYear(),d.getMonth()+1,d.getDate()) 90 | from = time - 2.592e+9 91 | 92 | if (data) { 93 | for (var i = 0; i < data.items.length; i++) { 94 | year=data.items[i].date.substring(0,4) 95 | month=data.items[i].date.substring(5,7) 96 | day=data.items[i].date.substring(8,10) 97 | 98 | if (Date.UTC(year,month,day) >= from) { 99 | volumes.push(data.items[i].volume) 100 | } 101 | } 102 | } 103 | 104 | return volumes; 105 | } 106 | -------------------------------------------------------------------------------- /IndustryJobs.gs: -------------------------------------------------------------------------------- 1 | /* 2 | Call this function like: 3 | =loadJobs("corp",4324234,"7okqZ1gOyG43243243242342qb2wkyd21C",90926985) 4 | =loadJobs("corp",4324234,"7okqZ1gOyG43243243242342qb2wkyd21C",90926985,1) 5 | and get all your jobs loaded into the sheet. I'd suggest doing it on a blank sheet, 6 | rather than in a sheet you have useful information on. 7 | 8 | The optional parameter at the end doesn't care what the value is, just if something is set or not. if it is, then the history is pulled 9 | 10 | 11 | It's 12 | jobID 13 | installerID 14 | installerName 15 | facilityID 16 | solarSystemID 17 | solarSystemName 18 | stationID 19 | activityID 20 | blueprintID 21 | blueprintTypeID 22 | blueprintTypeName 23 | blueprintLocationID 24 | outputLocationID 25 | runs 26 | successfulRuns 27 | cost 28 | teamID 29 | licensedRuns 30 | probability 31 | productTypeID 32 | productTypeName 33 | status 34 | timeInSeconds 35 | startDate 36 | endDate 37 | pauseDate 38 | completedDate 39 | completedCharacterID 40 | 41 | 42 | 43 | */ 44 | 45 | function loadJobs(type, keyID, vCode, characterID,history){ 46 | if (typeof history == 'undefined'){ 47 | historyurl=''; 48 | } else { 49 | historyurl='History'; 50 | } 51 | var jobs= new Array(); 52 | jobs.push(["jobID","installerID","installerName","facilityID","solarSystemID","solarSystemName","stationID","activityID","blueprintID","blueprintTypeID","blueprintTypeName" 53 | ,"blueprintLocationID","outputLocationID","runs","successfulRuns","cost","teamID","licensedRuns","probability","productTypeID","productTypeName","status","timeInSeconds", 54 | "startDate","endDate","pauseDate","completedDate","completedCharacterID"]); 55 | status={1:"Active",2:"Paused",3:"Ready",101:"Delivered",102:"Cancelled",103:"Reverted"}; 56 | var url = "https://api.eveonline.com/"+type+"/IndustryJobs"+historyurl+".xml.aspx?keyID="+keyID+"&vCode="+vCode+"&characterID="+characterID; 57 | var parameters = {method : "get", payload : ""}; 58 | var xmlFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 59 | var xml = XmlService.parse(xmlFeed); 60 | 61 | if(xml) { 62 | var rows=xml.getRootElement().getChild("result").getChild("rowset").getChildren("row"); 63 | for(var i = 0; i < rows.length; i++) { 64 | job=[parseInt(rows[i].getAttribute('jobID').getValue()), 65 | parseInt(rows[i].getAttribute('installerID').getValue()), 66 | rows[i].getAttribute('installerName').getValue(), 67 | parseInt(rows[i].getAttribute('facilityID').getValue()), 68 | parseInt(rows[i].getAttribute('solarSystemID').getValue()), 69 | rows[i].getAttribute('solarSystemName').getValue(), 70 | parseInt(rows[i].getAttribute('stationID').getValue()), 71 | parseInt(rows[i].getAttribute('activityID').getValue()), 72 | parseInt(rows[i].getAttribute('blueprintID').getValue()), 73 | parseInt(rows[i].getAttribute('blueprintTypeID').getValue()), 74 | rows[i].getAttribute('blueprintTypeName').getValue(), 75 | parseInt(rows[i].getAttribute('blueprintLocationID').getValue()), 76 | parseInt(rows[i].getAttribute('outputLocationID').getValue()), 77 | parseInt(rows[i].getAttribute('runs').getValue()), 78 | parseInt(rows[i].getAttribute('successfulRuns').getValue()), 79 | parseFloat(rows[i].getAttribute('cost').getValue()), 80 | parseInt(rows[i].getAttribute('teamID').getValue()), 81 | parseInt(rows[i].getAttribute('licensedRuns').getValue()), 82 | rows[i].getAttribute('probability').getValue(), 83 | parseInt(rows[i].getAttribute('productTypeID').getValue()), 84 | rows[i].getAttribute('productTypeName').getValue(), 85 | status[parseInt(rows[i].getAttribute('status').getValue())], 86 | parseInt(rows[i].getAttribute('timeInSeconds').getValue()), 87 | rows[i].getAttribute('startDate').getValue(), 88 | rows[i].getAttribute('endDate').getValue(), 89 | rows[i].getAttribute('pauseDate').getValue(), 90 | rows[i].getAttribute('completedDate').getValue(), 91 | parseInt(rows[i].getAttribute('completedCharacterID').getValue()) 92 | ]; 93 | jobs.push(job); 94 | } 95 | } 96 | return jobs; 97 | } 98 | 99 | 100 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 fuzzysteve 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LoadIndexes.gs: -------------------------------------------------------------------------------- 1 | /* 2 | A function for loading system industry indexes. 3 | 4 | 5 | */ 6 | 7 | 8 | function loadIndexes() { 9 | 10 | var url="https://esi.tech.ccp.is/latest/industry/systems/?datasource=tranquility" 11 | 12 | var parameters = {method : "get", payload : ""}; 13 | var jsonFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 14 | 15 | data = JSON.parse(jsonFeed) 16 | 17 | var systems=new Array() 18 | systems.push(['id','manufacturing','time efficiency','material efficiency','copying','invention','reaction']); 19 | if (data) { 20 | for (var i = 0; i < data.length; i++) { 21 | var system=new Object() 22 | for (var j =0; j< data[i].cost_indices.length;j++) { 23 | system[data[i].cost_indices[j].activity]=data[i].cost_indices[j].cost_index; 24 | } 25 | systems.push([data[i].solar_system_id, 26 | system['manufacturing'], 27 | system['researching_time_efficiency'], 28 | system['researching_material_efficiency'], 29 | system['copying'], 30 | system['invention'], 31 | system['reaction'], 32 | ]); 33 | 34 | } 35 | } 36 | return systems 37 | 38 | } 39 | -------------------------------------------------------------------------------- /MarketOrders.gs: -------------------------------------------------------------------------------- 1 | /* 2 | Because I'm doing some date math in this, this one's a trifle harder to use than some of the others. 3 | 4 | You'll need to add the moment.js library to the libraries for this sheet. Do so by using the Resources menu, then libraries. 5 | MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48 is the key to find it. Select version 9 and add it. 6 | 7 | The first version of the function just returns the raw data (plus a column for when it expires as that's handy) 8 | 9 | The second version depends on additional sheets, to fill in type data and station data. 10 | https://www.fuzzwork.co.uk/resources/typeids.csv into a sheet called typeid 11 | https://www.fuzzwork.co.uk/resources/stations.csv into a sheet called station 12 | 13 | 14 | You can do it with an importdata(), or paste it in. Pasting it will likely lead to better performance (as it won't reload it) but will need updating when new things come out. 15 | 16 | 17 | =loadMarketOrders("char",57828,"5T7GHu8583497584qFDhSH5o5HdMoYqhe4pwDSNtsA",90926985) 18 | =loadMarketOrdersResolved("char",57828,"5T7GHupiEtWTF9ZArmC895748935DhSH5o5HdMoYqhe4pwDSNtsA",90926985) 19 | 20 | For a quick method, copy the example sheet, put in proper values for the keyid, vcode and character id, and remove the initial ' 21 | 22 | https://docs.google.com/spreadsheets/d/12abDsXyq-Lj_yctkmCY0moZYUVC8gTRWnPC9Z02O2v8/edit?usp=sharing 23 | 24 | */ 25 | 26 | function loadMarketOrders(type, keyID, vCode, characterID){ 27 | var moment = Moment.load() 28 | var orders= new Array(); 29 | var url = "https://api.eveonline.com/"+type+"/MarketOrders.xml.aspx?keyID="+keyID+"&vCode="+vCode+"&characterID="+characterID; 30 | var parameters = {method : "get", payload : ""}; 31 | var xmlFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 32 | var xml = XmlService.parse(xmlFeed); 33 | if(xml) { 34 | var rows=xml.getRootElement().getChild("result").getChild("rowset").getChildren("row"); 35 | for(var i = 0; i < rows.length; i++) { 36 | order=[rows[i].getAttribute("orderID").getValue(), 37 | rows[i].getAttribute("charID").getValue(), 38 | rows[i].getAttribute("stationID").getValue(), 39 | parseInt(rows[i].getAttribute("volEntered").getValue()), 40 | parseInt(rows[i].getAttribute("volRemaining").getValue()), 41 | parseInt(rows[i].getAttribute("minVolume").getValue()), 42 | rows[i].getAttribute("orderState").getValue(), 43 | rows[i].getAttribute("typeID").getValue(), 44 | parseInt(rows[i].getAttribute("range").getValue()), 45 | rows[i].getAttribute("accountKey").getValue(), 46 | rows[i].getAttribute("duration").getValue(), 47 | parseFloat(rows[i].getAttribute("escrow").getValue()), 48 | parseFloat(rows[i].getAttribute("price").getValue()), 49 | rows[i].getAttribute("bid").getValue(), 50 | rows[i].getAttribute("issued").getValue(), 51 | moment(rows[i].getAttribute("issued").getValue(),"YYYY-MM-DD HH:mm:ss").add('days',parseInt(rows[i].getAttribute("duration").getValue())).format("YYYY-MM-DD HH:mm:ss") 52 | ]; 53 | orders.push(order); 54 | } 55 | } 56 | return orders; 57 | } 58 | 59 | 60 | 61 | 62 | function loadMarketOrdersResolved(type, keyID, vCode, characterID){ 63 | var moment = Moment.load() 64 | var orders= new Array(); 65 | var url = "https://api.eveonline.com/"+type+"/MarketOrders.xml.aspx?keyID="+keyID+"&vCode="+vCode+"&characterID="+characterID; 66 | var parameters = {method : "get", payload : ""}; 67 | var xmlFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 68 | var xml = XmlService.parse(xmlFeed); 69 | 70 | 71 | var orderStates = {0:'Open',1:'Closed',2:'Expired/fulfilled',3:'Cancelled',4:'Pending',5:'Character Deleted'}; 72 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 73 | var stationSheet = ss.getSheetByName("station"); 74 | var typeidSheet = ss.getSheetByName("typeid"); 75 | 76 | var stations=stationSheet.getDataRange().getValues(); 77 | var stationArray = new Array(); 78 | for(var i = 0; i < stations.length; i++) { 79 | var key = stations[i][0]+'_'; 80 | stationArray[key] = stations[i][1]; 81 | } 82 | 83 | var typeids=typeidSheet.getDataRange().getValues(); 84 | var typeidArray = new Array(); 85 | for(var i = 0; i < typeids.length; i++) { 86 | var key = typeids[i][0]+'_'; 87 | typeidArray[key] = typeids[i][1]; 88 | } 89 | 90 | if(xml) { 91 | var rows=xml.getRootElement().getChild("result").getChild("rowset").getChildren("row"); 92 | for(var i = 0; i < rows.length; i++) { 93 | order=[rows[i].getAttribute("orderID").getValue(), 94 | rows[i].getAttribute("charID").getValue(), 95 | stationArray[rows[i].getAttribute("stationID").getValue()+'_'], 96 | parseInt(rows[i].getAttribute("volEntered").getValue()), 97 | parseInt(rows[i].getAttribute("volRemaining").getValue()), 98 | parseInt(rows[i].getAttribute("minVolume").getValue()), 99 | orderStates[rows[i].getAttribute("orderState").getValue()], 100 | typeidArray[rows[i].getAttribute("typeID").getValue()+'_'], 101 | parseInt(rows[i].getAttribute("range").getValue()), 102 | rows[i].getAttribute("accountKey").getValue(), 103 | rows[i].getAttribute("duration").getValue(), 104 | parseFloat(rows[i].getAttribute("escrow").getValue()), 105 | parseFloat(rows[i].getAttribute("price").getValue()), 106 | parseInt(rows[i].getAttribute("bid").getValue())?'Buy':'Sell', 107 | rows[i].getAttribute("issued").getValue(), 108 | moment(rows[i].getAttribute("issued").getValue(),"YYYY-MM-DD HH:mm:ss").add('days',parseInt(rows[i].getAttribute("duration").getValue())).format("YYYY-MM-DD HH:mm:ss") 109 | ]; 110 | orders.push(order); 111 | } 112 | } 113 | return orders; 114 | } 115 | -------------------------------------------------------------------------------- /OutpostLoader.gs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Example Sheet 4 | https://docs.google.com/spreadsheets/d/1d3ixNx5hF5kfj2Zl3g46ODi3mqrb-AB7FDz4p4_8DCo/edit?usp=sharing 5 | 6 | 7 | */ 8 | /** 9 | * Creates a table of outpost information from the EVE API. 10 | * @return A table with columns of information in the following order: station ID, station name, station TypeID, solar system ID, owning corporation ID, owning corporation name. 11 | * @customfunction 12 | */ 13 | function loadOutposts(){ 14 | var outposts= new Array(); 15 | var url = "https://api.eveonline.com/eve/ConquerableStationList.xml.aspx"; 16 | var parameters = {method : "get", payload : ""}; 17 | var xmlFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 18 | var xml = XmlService.parse(xmlFeed); 19 | if(xml) { 20 | var rows=xml.getRootElement().getChild("result").getChild("rowset").getChildren("row"); 21 | for(var i = 0; i < rows.length; i++) { 22 | outpost=[rows[i].getAttribute("stationID").getValue(), 23 | rows[i].getAttribute("stationName").getValue(), 24 | rows[i].getAttribute("stationTypeID").getValue(), 25 | rows[i].getAttribute("solarSystemID").getValue(), 26 | rows[i].getAttribute("corporationID").getValue(), 27 | rows[i].getAttribute("corporationName").getValue() 28 | ] 29 | outposts.push(outpost); 30 | } 31 | } 32 | return outposts; 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | eve-googledocs-script 2 | ===================== 3 | 4 | Somewhere to stick functions for googledocs. 5 | 6 | So far, only the blueprint loading function exists. Just use the script editor to add the function in to the code.gs file. 7 | -------------------------------------------------------------------------------- /assetloader.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Reworked from https://gist.github.com/kriberg/abcae71b80213ae36b8f as google changed the way you handle xml 3 | * 4 | * load 5 | * https://www.fuzzwork.co.uk/resources/typeids.csv into a sheet called typeid 6 | * https://www.fuzzwork.co.uk/resources/stations.csv into a sheet called station 7 | * 8 | * you can always use =importdata() to do the import, if you want to. it'll make the sheet a bit slower, but things will update automatically. 9 | * 10 | **/ 11 | 12 | // globals to avoid stack size roof 13 | var assets = new Array(); 14 | var stationArray = new Array(); 15 | var typeidArray = new Array(); 16 | 17 | function office2station(locationID) { 18 | var locid = parseInt(locationID); 19 | if (locid >= 66000000 && locid <= 66014933) 20 | return locid - 6000001; 21 | if (locid >= 66014934 && locid <= 67999999) 22 | return locid - 6000000; 23 | return locid; 24 | 25 | } 26 | 27 | function parseAssets(rows, parent, locationID, location) { 28 | for (var i = 0; i < rows.length; i++) { 29 | rawQuantity = null; 30 | 31 | if (rows[i].getAttribute("locationID")) { 32 | locationID = office2station(rows[i].getAttribute("locationID").getValue()); 33 | 34 | if (stationArray) { 35 | var key = locationID + "_"; 36 | if (stationArray[key]) 37 | locationID = stationArray[key]; 38 | } 39 | } 40 | if (location) { 41 | if (location != locationID) { 42 | continue; 43 | } 44 | } 45 | if (rows[i].getAttribute("rawQuantity")) { 46 | rawQuantity = rows[i].getAttribute("rawQuantity").getValue(); 47 | } 48 | var asset = [rows[i].getAttribute("itemID").getValue(), 49 | rows[i].getAttribute("typeID").getValue(), 50 | parseInt(rows[i].getAttribute("typeID").getValue()), 51 | parseInt(rows[i].getAttribute("quantity").getValue()), 52 | rows[i].getAttribute("flag").getValue(), 53 | rows[i].getAttribute("singleton").getValue(), 54 | rawQuantity, 55 | locationID, 56 | parent]; 57 | 58 | if (typeidArray) { 59 | var key = asset[1] + "_"; 60 | if (typeidArray[key]) 61 | asset[1] = typeidArray[key]; 62 | } 63 | assets.push(asset); 64 | if (rows[i].getChild("rowset")) { 65 | parseAssets(rows[i].getChild("rowset").getChildren("row"), 66 | asset[0], 67 | asset[7]); 68 | } 69 | } 70 | } 71 | 72 | /** 73 | * @param {string} type api key type. corp or char 74 | * @param {number} keyID api key id 75 | * @param {string} vCode api vcode 76 | * @param {number} characterID Character id for api key 77 | * @param {number=} location location id to limit to. Optional 78 | * @return {array} array of assets 79 | * @customfunction 80 | */ 81 | 82 | function assetList(type, keyID, vCode, characterID, location) { 83 | var url = "https://api.eveonline.com/" + type + "/AssetList.xml.aspx?keyID=" + keyID + "&vCode=" + vCode + "&characterID=" + characterID; 84 | var parameters = { 85 | method : "get", 86 | payload : "" 87 | }; 88 | 89 | var xmlFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 90 | var xml = XmlService.parse(xmlFeed); 91 | 92 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 93 | var stationSheet = ss.getSheetByName("station"); 94 | var typeidSheet = ss.getSheetByName("typeid"); 95 | var stations = stationSheet.getDataRange().getValues(); 96 | for (var i = 0; i < stations.length; i++) { 97 | var key = stations[i][0] + '_'; 98 | stationArray[key] = stations[i][1]; 99 | } 100 | var typeids = typeidSheet.getDataRange().getValues(); 101 | for (var i = 0; i < typeids.length; i++) { 102 | var key = typeids[i][0] + '_'; 103 | typeidArray[key] = typeids[i][1]; 104 | } 105 | assets.push(["item id", "Type Name", "Type ID", "quantity", "flag", "singleton", "raw Quantity", "location id", "parent"]); 106 | if (xml) { 107 | var rows = xml.getRootElement().getChild("result").getChild("rowset").getChildren("row"); 108 | parseAssets(rows, null, null, location); 109 | } 110 | return assets; 111 | } 112 | -------------------------------------------------------------------------------- /blueprints.gs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Call this function like: 4 | =loadBlueprints("corp",4324234,"7okqZ1gOyG43243243242342qb2wkyd21C",90926985) 5 | 6 | and get all your blueprints loaded into the sheet. I'd suggest doing it on a blank sheet, 7 | rather than in a sheet you have useful information on. 8 | 9 | It's 'blueprint ID','location ID','Typeid of blueprint','name of blueprint','which hangar it's in', 10 | 'quantity. -2 for a BPC, -1 for a BPO, a number for stacked BPOs',TE,ME,'runs, -1 for a BPO' 11 | 12 | */ 13 | /** 14 | * Creates a table of information on blueprints retrieved from the EVE API. 15 | * @param {string} type This should be set to "char" or "corp" depending on the type of API key in use. 16 | * @param {number} keyID This should be set to the keyID given by your API key. 17 | * @param {string} vCode This should be set to the verification code given by your API key. 18 | * @param {number} characterID This should be set to the specific character for which you would like to retrieve the blueprint data. 19 | * @returns A table with information in the following order: 'blueprint ID','location ID','Typeid of blueprint','name of blueprint','which hangar it's in', 'quantity. -2 for a BPC, -1 for a BPO, a number for stacked BPOs',TE,ME,'runs, -1 for a BPO' 20 | * @customfunction 21 | */ 22 | function loadBlueprints(type, keyID, vCode, characterID){ 23 | var blueprints= new Array(); 24 | var url = "https://api.eveonline.com/"+type+"/Blueprints.xml.aspx?keyID="+keyID+"&vCode="+vCode+"&characterID="+characterID; 25 | var parameters = {method : "get", payload : ""}; 26 | var xmlFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 27 | var xml = XmlService.parse(xmlFeed); 28 | 29 | if(xml) { 30 | var rows=xml.getRootElement().getChild("result").getChild("rowset").getChildren("row"); 31 | for(var i = 0; i < rows.length; i++) { 32 | blueprint=[rows[i].getAttribute("itemID").getValue(), 33 | rows[i].getAttribute("locationID").getValue(), 34 | rows[i].getAttribute("typeID").getValue(), 35 | rows[i].getAttribute("typeName").getValue(), 36 | rows[i].getAttribute("flagID").getValue(), 37 | rows[i].getAttribute("quantity").getValue(), 38 | rows[i].getAttribute("timeEfficiency").getValue(), 39 | rows[i].getAttribute("materialEfficiency").getValue(), 40 | rows[i].getAttribute("runs").getValue()] 41 | blueprints.push(blueprint); 42 | } 43 | } 44 | return blueprints; 45 | } 46 | -------------------------------------------------------------------------------- /citadelmarket.gs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | see https://www.fuzzwork.co.uk/2017/03/14/using-esi-googledocs/ for install details. 5 | 6 | 7 | Needs work, as it reauths for each call. As it can't store the access token or expiry in the sheet. 8 | 9 | 10 | 11 | 12 | 13 | */ 14 | 15 | function getSetup() { 16 | var config={}; 17 | var namedRanges = SpreadsheetApp.getActiveSpreadsheet().getNamedRanges(); 18 | for (var i = 0; i < namedRanges.length; i++) { 19 | switch (namedRanges[i].getName()) { 20 | case 'clientid': 21 | config.clientid=namedRanges[i].getRange().getCell(1, 1).getValue() ; 22 | break; 23 | case 'secret': 24 | config.secret=namedRanges[i].getRange().getCell(1, 1).getValue() ; 25 | break; 26 | case 'refresh': 27 | config.refreshtoken=namedRanges[i].getRange().getCell(1, 1).getValue() ; 28 | break; 29 | } 30 | 31 | } 32 | var documentProperties = PropertiesService.getDocumentProperties(); 33 | config.expires = documentProperties.getProperty('oauth_expires'); 34 | config.access_token = documentProperties.getProperty('access_token') 35 | return config; 36 | } 37 | 38 | function getAccessToken(config) { 39 | 40 | if (Date.now()>config.expires) { 41 | 42 | var url = 'https://login.eveonline.com/oauth/token?' 43 | + 'grant_type=refresh_token' 44 | + '&refresh_token='+config.refreshtoken; 45 | 46 | var code=Utilities.base64Encode(config.clientid+':'+config.secret); 47 | 48 | var headers = { 49 | 'Authorization': 'Basic '+code, 50 | 'Content-Type': 'application/x-www-form-urlencoded', 51 | }; 52 | var parameters = { 53 | 'method': 'post', 54 | 'headers': headers, 55 | }; 56 | var response = UrlFetchApp.fetch(url, parameters).getContentText(); 57 | var json = JSON.parse(response); 58 | var access_token = json['access_token']; 59 | 60 | config.access_token=access_token; 61 | config.expires=Date.now()+1200000 62 | var documentProperties = PropertiesService.getDocumentProperties(); 63 | documentProperties.setProperty('access_token',access_token) 64 | documentProperties.setProperty('oauth_expires',config.expires) 65 | 66 | 67 | } 68 | 69 | return config; 70 | 71 | } 72 | 73 | 74 | 75 | 76 | 77 | function getCitadel(citadelid) { 78 | 79 | var config=getSetup(); 80 | 81 | config=getAccessToken(config); 82 | 83 | var url = 'https://esi.tech.ccp.is/latest/markets/structures/'+citadelid+'/'; 84 | 85 | 86 | var parameters = {method : "get", headers : {'Authorization':'Bearer '+ config.access_token}}; 87 | 88 | var jsonFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 89 | var json = JSON.parse(jsonFeed); 90 | var prices=[]; 91 | prices.push(['duration','buy','issued','location','min volume','order id','price','range','typeid','volume remaining','total volume']) 92 | if(json) { 93 | for(i in json) { 94 | var price=[json[i].duration, 95 | json[i].is_buy_order, 96 | json[i].issued, 97 | json[i].location_id, 98 | json[i].min_volume, 99 | json[i].order_id, 100 | json[i].price, 101 | json[i].range, 102 | json[i].type_id, 103 | json[i].volume_remain, 104 | json[i].volume_total 105 | ]; 106 | prices.push(price); 107 | } 108 | } 109 | return prices; 110 | } 111 | -------------------------------------------------------------------------------- /esi-nameloader.gs: -------------------------------------------------------------------------------- 1 | /* 2 | * Loads names from ESI, using ids 3 | * @param nameids A range where the nameids can be found 4 | * @return the names of the people 5 | * @customfunction 6 | */ 7 | 8 | function nameloader(nameIDs) { 9 | 10 | if (typeof nameIDs == 'undefined'){ 11 | throw 'need name ids'; 12 | } 13 | 14 | var names = new Array(); 15 | var dirtynameids = new Array(); 16 | var cleannameids = new Array(); 17 | var url="https://esi.evetech.net/latest/universe/names/?datasource=tranquility"; 18 | 19 | nameIDs.forEach (function (row) { 20 | row.forEach ( function (cell) { 21 | if (typeof(cell) === 'number' ) { 22 | dirtynameids.push(cell); 23 | } 24 | }); 25 | }); 26 | cleannameids = dirtynameids.filter(function(v,i,a) { 27 | return a.indexOf(v)===i; 28 | }); 29 | 30 | var parameters = {method : "post", payload : ""}; 31 | 32 | var o,j,temparray,chunk = 100; 33 | for (o=0,j=cleannameids.length; o < j; o+=chunk) { 34 | temparray = cleannameids.slice(o,o+chunk); 35 | parameters['payload']=JSON.stringify(temparray) 36 | var jsonfeed = UrlFetchApp.fetch(url, parameters).getContentText(); 37 | var datafeed=JSON.parse(jsonfeed); 38 | for(var i = 0; i < datafeed.length; i++) { 39 | var namedata=[parseInt(datafeed[i]['id']),datafeed[i]['name']]; 40 | names.push(namedata); 41 | } 42 | } 43 | return names; 44 | } 45 | -------------------------------------------------------------------------------- /industryFigures.gs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Creates 2 new sheets, and 2 new menu options. 4 | 5 | Paste into the script editor, then run the onOpen() function. it'll ask for some privileges. grant them, then go back to the sheet. 6 | you'll have a new API menu, with 2 options. each option will create the sheet it needs. 7 | 8 | 9 | 10 | */ 11 | 12 | 13 | function onOpen() { 14 | var ui = SpreadsheetApp.getUi(); 15 | ui.createMenu('API') 16 | .addItem('Update Indexes', 'loadIndexes') 17 | .addItem('Update Industry Prices', 'updateIndustryPrices') 18 | .addToUi(); 19 | } 20 | 21 | 22 | function loadIndexes() { 23 | 24 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 25 | 26 | try {ss.setActiveSheet(ss.getSheetByName("indexes"));} 27 | catch (e) {ss.insertSheet("indexes");} 28 | 29 | var indexsheet=ss.getSheetByName("indexes") 30 | indexsheet.clear() 31 | var url="https://esi.tech.ccp.is/v1/industry/systems/?datasource=tranquility" 32 | 33 | var parameters = {method : "get", payload : ""}; 34 | var jsonFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 35 | 36 | data = JSON.parse(jsonFeed) 37 | 38 | var systems=new Array() 39 | systems.push(['id','manufacturing','time efficiency','material efficiency','copying','invention','reaction']); 40 | if (data) { 41 | for (var i = 0; i < data.length; i++) { 42 | var system=new Object() 43 | for (var j =0; j< data[i].cost_indices.length;j++) { 44 | system[data[i].cost_indices[j].activity]=data[i].cost_indices[j].cost_index; 45 | } 46 | systems.push([data[i].solar_system_id, 47 | system['manufacturing'], 48 | system['researching_time_efficiency'], 49 | system['researching_material_efficiency'], 50 | system['copying'], 51 | system['invention'], 52 | system['reaction'], 53 | ]); 54 | 55 | } 56 | } 57 | indexsheet.insertRowsAfter(1,systems.length) 58 | indexsheet.getRange(indexsheet.getLastRow()+1, 1, systems.length, systems[0].length).setValues(systems) 59 | var rows = indexsheet.getRange(2, 1, indexsheet.getLastRow() - 1, indexsheet.getLastColumn()); 60 | rows.sort(1) 61 | } 62 | 63 | 64 | 65 | function updateIndustryPrices() { 66 | 67 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 68 | 69 | try {ss.setActiveSheet(ss.getSheetByName("prices"));} 70 | catch (e) {ss.insertSheet("prices");} 71 | 72 | var pricesheet=ss.getSheetByName("prices") 73 | pricesheet.clear() 74 | 75 | var url="https://esi.tech.ccp.is/v1/markets/prices/?datasource=tranquility" 76 | 77 | var parameters = {method : "get", payload : ""}; 78 | var jsonFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 79 | 80 | data = JSON.parse(jsonFeed) 81 | 82 | var prices=new Array() 83 | prices.push(['id','average','adjusted']); 84 | if (data) { 85 | for (var i = 0; i < data.length; i++) { 86 | prices.push([data[i].type_id, 87 | data[i].average_price, 88 | data[i].adjusted_price, 89 | ]); 90 | 91 | } 92 | } 93 | pricesheet.insertRowsAfter(1,prices.length) 94 | pricesheet.getRange(pricesheet.getLastRow()+1, 1, prices.length, prices[0].length).setValues(prices) 95 | var rows = pricesheet.getRange(2, 1, pricesheet.getLastRow() - 1, pricesheet.getLastColumn()); 96 | rows.sort(1) 97 | 98 | } 99 | -------------------------------------------------------------------------------- /kills.gs: -------------------------------------------------------------------------------- 1 | /* 2 | https://docs.google.com/spreadsheets/d/17XjDQRArWKfYEA6xWmSwgsE6gDp_Lbj0lZdtxHIFe5A/edit?usp=sharing 3 | */ 4 | function loadKills(){ 5 | var kills= new Array(); 6 | var url = "https://api.eveonline.com/map/Kills.xml.aspx"; 7 | var parameters = {method : "get", payload : ""}; 8 | var xmlFeed = UrlFetchApp.fetch(url, parameters).getContentText(); 9 | var xml = XmlService.parse(xmlFeed); 10 | if(xml) { 11 | var rows=xml.getRootElement().getChild("result").getChild("rowset").getChildren("row"); 12 | for(var i = 0; i < rows.length; i++) { 13 | system=[parseInt(rows[i].getAttribute("solarSystemID").getValue()), 14 | parseInt(rows[i].getAttribute("shipKills").getValue()), 15 | parseInt(rows[i].getAttribute("factionKills").getValue()), 16 | parseInt(rows[i].getAttribute("podKills").getValue()), 17 | ] 18 | kills.push(system); 19 | } 20 | } 21 | return kills; 22 | } 23 | -------------------------------------------------------------------------------- /moons/FormSubmissionVersion.gs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This one is a bit harder to set up. 4 | 5 | First, create a form. This must have a field called 'Moon data'. Capitalization is important. It can contain any other fields you want. 6 | 7 | https://forms.google.com 8 | 9 | Once the form exists, click on 'responses'. There will be a green icon. the tool tip will be 'view responses in google sheets.' hit it 10 | 11 | this will create a new sheet. 12 | 13 | create a new page on it called 'processed' 14 | 15 | go to the script editor. paste in the code below. 16 | 17 | name the project 18 | 19 | then go to edit-> current project's triggers. 20 | 21 | create a new trigger. 22 | 23 | should be: processMoon, from spreadsheet, on form submit. 24 | 25 | When you save, it'll throw security warnings. work your way through them. 26 | 27 | That should then be it. 28 | 29 | 30 | */ 31 | function romanToNumber(str1) { 32 | if(str1 == null) return -1; 33 | var num = char_to_int(str1.charAt(0)); 34 | var pre, curr; 35 | 36 | for(var i = 1; i < str1.length; i++) { 37 | curr = char_to_int(str1.charAt(i)); 38 | pre = char_to_int(str1.charAt(i-1)); 39 | if(curr <= pre) { 40 | num += curr; 41 | } else { 42 | num = num - pre*2 + curr; 43 | } 44 | } 45 | 46 | return num; 47 | } 48 | 49 | function char_to_int(c){ 50 | switch (c){ 51 | case 'I': return 1; 52 | case 'V': return 5; 53 | case 'X': return 10; 54 | case 'L': return 50; 55 | case 'C': return 100; 56 | case 'D': return 500; 57 | case 'M': return 1000; 58 | default: return -1; 59 | } 60 | } 61 | 62 | function reformatName(name){ 63 | var re=/(.*) (\w+?) \- Moon (\d+?)$/; 64 | 65 | m=re.exec(name); 66 | 67 | return Array(m[1],romanToNumber(m[2]),m[3]); 68 | 69 | }; 70 | 71 | 72 | function processMoon(e) { 73 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 74 | var moonsheet = ss.getSheetByName("processed"); 75 | 76 | moondata=e.namedValues['Moon data'][0] 77 | 78 | oreArray = moondata.match(/[^\r\n]+/g); 79 | var orere=/^\W*(\w+?\s?\w+?)\W+([\d.]+)\W+(\d+)\W+(\d+)\W+(\d+)\W+(\d+)\W*$/; 80 | planet=""; 81 | pivot=0; 82 | row=new Array(); 83 | start=1; 84 | for (var i = 0, len = oreArray.length; i < len; i++) { 85 | if (oreArray[i].substring(0,4) === "Moon") { 86 | continue; 87 | } 88 | if (oreArray[i][0] === " " || oreArray[i][0] === "\t") { 89 | ore=oreArray[i].trim().trim("\t"); 90 | m=orere.exec(ore); 91 | ore=[m[1],m[2],m[3],m[4],m[5]]; 92 | if (pivot) { 93 | row=row.concat(ore); 94 | } else { 95 | row=new Array(); 96 | row=row.concat(planet,ore); 97 | moonsheet.appendRow(row) 98 | } 99 | } else { 100 | planet=reformatName(oreArray[i]); 101 | if (pivot) { 102 | if (!start) { 103 | moonsheet.appendRow(row); 104 | } else { 105 | start=0; 106 | } 107 | row=new Array(); 108 | row=row.concat(planet); 109 | } 110 | } 111 | 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /moons/code.gs: -------------------------------------------------------------------------------- 1 | function onOpen() { 2 | var ui = SpreadsheetApp.getUi(); 3 | ui.createMenu('moons') 4 | .addItem('add moons', 'addMoons') 5 | .addToUi(); 6 | } 7 | 8 | function romanToNumber(str1) { 9 | if(str1 == null) return -1; 10 | var num = char_to_int(str1.charAt(0)); 11 | var pre, curr; 12 | 13 | for(var i = 1; i < str1.length; i++) { 14 | curr = char_to_int(str1.charAt(i)); 15 | pre = char_to_int(str1.charAt(i-1)); 16 | if(curr <= pre) { 17 | num += curr; 18 | } else { 19 | num = num - pre*2 + curr; 20 | } 21 | } 22 | 23 | return num; 24 | } 25 | 26 | function char_to_int(c){ 27 | switch (c){ 28 | case 'I': return 1; 29 | case 'V': return 5; 30 | case 'X': return 10; 31 | case 'L': return 50; 32 | case 'C': return 100; 33 | case 'D': return 500; 34 | case 'M': return 1000; 35 | default: return -1; 36 | } 37 | } 38 | 39 | function reformatName(name){ 40 | var re=/(.*) (\w+?) \- Moon (\d+?)$/; 41 | 42 | m=re.exec(name); 43 | 44 | return Array(m[1],romanToNumber(m[2]),m[3]); 45 | 46 | }; 47 | 48 | 49 | function addMoons() { 50 | var html = HtmlService.createHtmlOutputFromFile('input'); 51 | SpreadsheetApp.getUi().showModalDialog(html, 'Enter Moon Data'); 52 | } 53 | 54 | function processMoon(moondata) { 55 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 56 | var moonsheet = ss.getSheetByName("moons"); 57 | 58 | oreArray = moondata.match(/[^\r\n]+/g); 59 | var orere=/^\W*(\w+?\s?\w+?)\W+([\d.]+)\W+(\d+)\W+(\d+)\W+(\d+)\W+(\d+)\W*$/; 60 | planet=""; 61 | pivot=0; 62 | row=new Array(); 63 | start=1; 64 | for (var i = 0, len = oreArray.length; i < len; i++) { 65 | if (oreArray[i].substring(0,4) === "Moon") { 66 | continue; 67 | } 68 | if (oreArray[i][0] === " " || oreArray[i][0] === "\t") { 69 | ore=oreArray[i].trim().trim("\t"); 70 | m=orere.exec(ore); 71 | ore=[m[1],m[2],m[3],m[4],m[5]]; 72 | if (pivot) { 73 | row=row.concat(ore); 74 | } else { 75 | row=new Array(); 76 | row=row.concat(planet,ore); 77 | moonsheet.appendRow(row) 78 | } 79 | } else { 80 | planet=reformatName(oreArray[i]); 81 | if (pivot) { 82 | if (!start) { 83 | moonsheet.appendRow(row); 84 | } else { 85 | start=0; 86 | } 87 | row=new Array(); 88 | row=row.concat(planet); 89 | } 90 | } 91 | 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /moons/input.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |