├── README.md
├── moons
├── input.html
├── code.gs
└── FormSubmissionVersion.gs
├── kills.gs
├── LICENSE
├── LoadIndexes.gs
├── esi-nameloader.gs
├── OutpostLoader.gs
├── sheetLoader.gs
├── blueprints.gs
├── FuzzworkMarket.gs
├── HistoryGrabber.gs
├── FuzzworkMarketPrices-Menu.gs
├── industryFigures.gs
├── citadelmarket.gs
├── assetloader.gs
├── IndustryJobs.gs
├── MarketOrders.gs
├── EveCentralPrices.gs
└── ESIWalletPull.gs
/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 |
--------------------------------------------------------------------------------
/moons/input.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/sheetLoader.gs:
--------------------------------------------------------------------------------
1 | /*
2 | The beginning of a loader for a character sheet.
3 |
4 |
5 | =loadSheet(keyid,"vcode",characterid)
6 |
7 | it prepends all skill typeids with skill-, this is so,
8 | if you expand it to also pull things like implants, you can still easily look them up.
9 |
10 |
11 | To pull a specific skill value:
12 | =vlookup("skill-3303",Sheet1!A:C,3,false)
13 |
14 |
15 | If you want to do it differently replace
16 | skill=['skill-'+skills[j].getAttribute("typeID").getValue(),
17 |
18 | with
19 |
20 | skill=['skill',parseInt(skills[j].getAttribute("typeID").getValue()),
21 |
22 | =query(Sheet1!A:D,CONCATENATE("select D where A='skill' and B=",B2,""))
23 |
24 |
25 | Which is a little messier to look at and use.
26 |
27 | */
28 |
29 |
30 | function loadSheet(keyID, vCode, characterID){
31 | var sheet= new Array();
32 | var url = "https://api.eveonline.com/char/charactersheet.xml.aspx?keyID="+keyID+"&vCode="+vCode+"&characterID="+characterID;
33 | var parameters = {method : "get", payload : ""};
34 | var xmlFeed = UrlFetchApp.fetch(url, parameters).getContentText();
35 | var xml = XmlService.parse(xmlFeed);
36 | if(xml) {
37 | var rows=xml.getRootElement().getChild("result").getChildren("rowset");
38 | for (var i = 0; i < rows.length; i++) {
39 | if (rows[i].getAttribute("name").getValue()=='skills') {
40 | var skills=rows[i].getChildren("row")
41 | for(var j = 0; j < skills.length; j++) {
42 | skill=['skill-'+skills[j].getAttribute("typeID").getValue(),
43 | parseInt(skills[j].getAttribute("skillpoints").getValue()),
44 | parseInt(skills[j].getAttribute("level").getValue()),
45 | parseInt(skills[j].getAttribute("published").getValue())
46 | ]
47 | sheet.push(skill);
48 | }
49 | }
50 | }
51 | }
52 | return sheet;
53 | }
54 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------