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.components.register('fight-timeline', { viewModel: function(params) { var self = this; // Data: value is either null, 'like', or 'dislike' this.fight = params.value.fight(); this.actors = params.value.actors; console.log("fight-timeline: Got ",params.value); // Behaviors self.calculateDivStyle = function(timestamp, ability) { var fight_length = self.fight.end_time - self.fight.start_time; console.log("Fight was "+fight_length); var cooldown = window.trackedCooldowns[ability.guid].cooldown; console.log("Use was at "+timestamp+" and cd is "+cooldown); var startpct = timestamp / fight_length * 100; var widthpct = cooldown / fight_length * 100; console.log("Cooldown started at "+startpct+"% and endured "+widthpct+"%"); var res = {color: "teal", "margin-left": startpct+"%", width:widthpct+"%"}; return res; }; }, template: '
\ \ \ \
' }); // 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.formatFightTime = function(fight) { return self.formatTime(fight.end_time - fight.start_time); }; self.formatTime = function(time) { let secs = 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); console.log("trackedActors: ",self.trackedActors()); }; 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); } event.timestamp = event.timestamp - fight.start_time; 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; }