|
|
|
const fflogsBase = "https://www.fflogs.com:443/v1/report/";
|
|
|
|
const fflogsFightsAPI = fflogsBase + "fights/"
|
|
|
|
const fflogsEventsAPI = fflogsBase + "events/"
|
|
|
|
const api = "?api_key=";
|
|
|
|
// ?end=1591130148287&sourceid=5
|
|
|
|
|
|
|
|
var indexViewModel;
|
|
|
|
var classColors = {
|
|
|
|
"Scholar": "#4c49b2",
|
|
|
|
"WhiteMage": "#c7bf8e",
|
|
|
|
"Astrologian": "#8c501e",
|
|
|
|
"Paladin": "#8aa8a8",
|
|
|
|
"Gunbreaker": "#6c6433",
|
|
|
|
"Warrior": "#610e0a",
|
|
|
|
"DarkKnight": "#241011",
|
|
|
|
"Ninja": "#b30000",
|
|
|
|
"Dragoon": "#3b4ba0",
|
|
|
|
"Monk": "#c58d1c",
|
|
|
|
"Samurai": "#9e6d35",
|
|
|
|
"RedMage": "#47132a",
|
|
|
|
"BlackMage": "#261947",
|
|
|
|
"Summoner": "#59922b",
|
|
|
|
"Dancer": "#ceb8ab",
|
|
|
|
"Machinist": "#6c6433",
|
|
|
|
"Barde": "#6d8432"
|
|
|
|
};
|
|
|
|
|
|
|
|
var trackedCooldowns = {
|
|
|
|
7436: {name: "Chain Stratagem", cooldown: 120000},
|
|
|
|
16536: {name: "Temperance", cooldown: 180000},
|
|
|
|
2258: {name: "Trick Attack", cooldown: 60000}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Do stuff when HTML parsing is ready
|
|
|
|
$(() => {
|
|
|
|
ko.bindingHandlers.foreachprop = {
|
|
|
|
transformObject: function (obj) {
|
|
|
|
var properties = [];
|
|
|
|
ko.utils.objectForEach(obj, function (key, value) {
|
|
|
|
properties.push({ key: key, value: value });
|
|
|
|
});
|
|
|
|
return properties;
|
|
|
|
},
|
|
|
|
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
|
|
|
|
var properties = ko.pureComputed(function () {
|
|
|
|
var obj = ko.utils.unwrapObservable(valueAccessor());
|
|
|
|
return ko.bindingHandlers.foreachprop.transformObject(obj);
|
|
|
|
});
|
|
|
|
ko.applyBindingsToNode(element, { foreach: properties }, bindingContext);
|
|
|
|
return { controlsDescendantBindings: true };
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Document is ready
|
|
|
|
function IndexViewModel() {
|
|
|
|
var self = this;
|
|
|
|
self.apiKey = ko.observable(localStorage.getItem("apikey"));
|
|
|
|
self.logID = ko.observable(localStorage.getItem("fflogid"));
|
|
|
|
self.fights = ko.observableArray();
|
|
|
|
self.friendlies = ko.observableArray();
|
|
|
|
self.enemies = ko.observableArray();
|
|
|
|
self.trackedActors = ko.observableArray();
|
|
|
|
self.displayFightPicker = ko.observable(false);
|
|
|
|
self.selectedFight = ko.observable();
|
|
|
|
|
|
|
|
self.getLog = async function() {
|
|
|
|
var log = await fetchLog(self.logID());
|
|
|
|
|
|
|
|
self.fights(log["fights"]);
|
|
|
|
self.friendlies(log["friendlies"]);
|
|
|
|
self.enemies(log["enemies"]);
|
|
|
|
self.displayFightPicker(true);
|
|
|
|
};
|
|
|
|
|
|
|
|
self.formatTime = function(fight) {
|
|
|
|
let secs = (fight.end_time - fight.start_time)/1000;
|
|
|
|
let mins = Math.floor(secs / 60);
|
|
|
|
let rest = Math.floor(secs % 60);
|
|
|
|
return mins+"m"+rest+"s";
|
|
|
|
};
|
|
|
|
|
|
|
|
self.apiKeyChanged = function() {
|
|
|
|
console.log("Setting apiKey to ",self.apiKey());
|
|
|
|
localStorage.setItem("apikey",self.apiKey());
|
|
|
|
localStorage.setItem("fflogid", self.logID());
|
|
|
|
};
|
|
|
|
|
|
|
|
self.fightChanged = async function() {
|
|
|
|
console.log("Fight has changed to ",self.selectedFight());
|
|
|
|
var events = await fetchEvents(self.selectedFight());
|
|
|
|
|
|
|
|
var actors = await filterEvents(self.selectedFight(),events);
|
|
|
|
/*
|
|
|
|
for(var actor of actors) {
|
|
|
|
var updated = false;
|
|
|
|
for(var oldactor of self.trackedActors()) {
|
|
|
|
if(actor.id === oldactor.id) {
|
|
|
|
oldactor.trackedEvents(actor.trackedEvents());
|
|
|
|
oldactor.trackedEvents.valueHasMutated();
|
|
|
|
updated = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!updated) {
|
|
|
|
self.trackedActors.push(actor);
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
//FIXME: This is a hack, we should instead somehow update the trackedEvents observable so only this part is rerendered
|
|
|
|
self.trackedActors([]);
|
|
|
|
self.trackedActors(actors);
|
|
|
|
for(var actor of self.trackedActors()) {
|
|
|
|
console.log("tracked: ",actor.trackedEvents());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
self.textColor = function(job) {
|
|
|
|
return classColors[job.type];
|
|
|
|
};
|
|
|
|
|
|
|
|
self.actorIDToName = function(id) {
|
|
|
|
for(var actor of self.friendlies()) {
|
|
|
|
if(id == actor.id) {
|
|
|
|
return actor.name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(var actor of self.enemies()) {
|
|
|
|
if(id == actor.id) {
|
|
|
|
return actor.name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
};
|
|
|
|
|
|
|
|
self.getActorByID = function(id) {
|
|
|
|
for(var actor of self.friendlies()) {
|
|
|
|
if(id == actor.id) {
|
|
|
|
return actor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(var actor of self.enemies()) {
|
|
|
|
if(id == actor.id) {
|
|
|
|
return actor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
indexViewModel = new IndexViewModel();
|
|
|
|
ko.applyBindings(indexViewModel);
|
|
|
|
});
|
|
|
|
|
|
|
|
async function filterEvents(fight, events) {
|
|
|
|
var result = [];
|
|
|
|
for(var event of events) {
|
|
|
|
// Do we even care about this cast?
|
|
|
|
if(!(event.ability.guid in trackedCooldowns)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
var found = false;
|
|
|
|
for(var actor of result) {
|
|
|
|
if(actor.id == event.sourceID) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!found) {
|
|
|
|
console.log("Found new actor: "+event.sourceID);
|
|
|
|
var actor = indexViewModel.getActorByID(event.sourceID);
|
|
|
|
actor.trackedEvents = ko.observableArray();
|
|
|
|
result.push(actor);
|
|
|
|
}
|
|
|
|
actor.trackedEvents.push(event);
|
|
|
|
console.log(event);
|
|
|
|
}
|
|
|
|
console.log("Generated arrays: ",result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function fetchEvents(fight) {
|
|
|
|
let baseUrl = fflogsEventsAPI + "casts/" + indexViewModel.logID() + api + indexViewModel.apiKey() + "&translate=true" + "&end=" + fight.end_time;
|
|
|
|
let start_time = fight.start_time;
|
|
|
|
let result = [];
|
|
|
|
|
|
|
|
let snip = {};
|
|
|
|
do {
|
|
|
|
let url = baseUrl + "&start=" + start_time;
|
|
|
|
console.log("Requesting "+url);
|
|
|
|
snip = await fetchEventsSnippet(url);
|
|
|
|
for(var e of snip.events) {
|
|
|
|
result.push(e);
|
|
|
|
}
|
|
|
|
//result = result.concat(snip.events);
|
|
|
|
start_time = snip.nextPageTimestamp;
|
|
|
|
} while(snip.nextPageTimestamp)
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function fetchEventsSnippet(url) {
|
|
|
|
var res = await fetch(url);
|
|
|
|
if (!res.ok) {
|
|
|
|
console.log(res);
|
|
|
|
throw Error(res.text);
|
|
|
|
}
|
|
|
|
var events = await res.json();
|
|
|
|
|
|
|
|
console.log(events);
|
|
|
|
return events;
|
|
|
|
}
|
|
|
|
|
|
|
|
// API request um JSON zu erhalten
|
|
|
|
async function fetchLog(logId) {
|
|
|
|
let url = fflogsFightsAPI + logId + api + indexViewModel.apiKey();
|
|
|
|
|
|
|
|
console.log("Requesting "+logId);
|
|
|
|
var res = await fetch(url);
|
|
|
|
if (!res.ok) {
|
|
|
|
console.log(res);
|
|
|
|
throw Error(res.text);
|
|
|
|
}
|
|
|
|
var log = await res.json();
|
|
|
|
|
|
|
|
//get specific fight data
|
|
|
|
console.log(log);
|
|
|
|
return log;
|
|
|
|
}
|