- // ==UserScript==
- // @name 石之家logs成分查询
- // @name:en stonesLogsViewer
- // @namespace Umi
- // @version 1.0
- // @description 一个通过石之家查询fflogs的小插件
- // @description:en stonesLogsViewer--
- // @author Umi
- // @match *://ff14risingstones.web.sdo.com/*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=undefined.
- // @grant GM_xmlhttpRequest
- // @license MIT
- // ==/UserScript==
-
- const delay = 500;
- //api token 可以使用自己的token
- const apiToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiI5YWUxMzk2ZC0xNmVmLTQ4NjEtOGIwZC05ZTc4NDRkM2JjMWMiLCJqdGkiOiJmZmVkMmI4ZTllNjUwNWI0ZTk4ZGNmN2Y0ZGZkZTlmZjg0MjE3YWIxMjE1ZDk1ZjhkNDBmYjIyMjlkNjE0MTQwODYwNjU1YTdmMzlmYjExMiIsImlhdCI6MTcwMjkyMTY1OS43MTIzNjIsIm5iZiI6MTcwMjkyMTY1OS43MTIzNjUsImV4cCI6MTczNDAyNTY1OS43MDMxOTcsInN1YiI6IiIsInNjb3BlcyI6WyJ2aWV3LXVzZXItcHJvZmlsZSIsInZpZXctcHJpdmF0ZS1yZXBvcnRzIl19.TQvn0mwLoEEppHcxuPnXINVLRjrLM0givJ-sltQfHEUFXVJj_r_QLS57ieDAlsjkzOH9ZMlrdBcK0fbMnDa93Jru95-CwNgjl261nYuBYmemAIkNWgVAwsOjXvNm4feoelRHtz8bpbZmCQ1S8FM8d0gwolueZp5t6Kku2Cpb2qaWv_cERh-uO44smPgiER4Z9j33JlfWvkC8brljVALcKjnu7i27R-qD6hBQhicZN7DJVnJkdZGceu9Kaoq0fJO0wr0E8s8BnWQTLJwW3uGSzXrQGUWATxrwALAqIa_2kjKnaC0sXGUnUGQZdckpW6VGHPnfCGslNarviK72n9kfIOlpJVhL-7T360-CgpEVpnFVxfQCTz0ZnRhqxwy9ixZ7OyAY8ZpQTerkGDb2HlZTTCBB-gOdrUmQvDDEfKnGPfuuHSL4TrY6Ndo-Ips8NAUy67nqGaqAUBmUi9MqA-ZL8oqtW3J_Q0HfbTVPk8RvpCelij9zQpC_LSc0kz46vnr47teiEd_4eY8zW6ataCRP4B7epp0aEp6e-UkJjZ05DBgzYwB-aromyrBB6cJPHOX61ywWoEJIYMb8RL6HdGE8vSxhYTrXZfcUBcmkvVZHFHkvmR4MIJ5zjpESr0gq8_gp1ol_FapBmt39Mpuk0GDRUsTCNJAtp6FRcAY8ul4PUJs";
- const url = "https://cn.fflogs.com/api/v2/client";
- const zones = [
- {
- "id": 54,
- "name": "万魔殿 荒天之狱",
- "difficulty": 101
- },
- {
- "id": 49,
- "name": "万魔殿 炼净之狱",
- "difficulty": 101
- },
- {
- "id": 44,
- "name": "万魔殿 边境之狱",
- "difficulty": 101
- },
- {
- "id": 53,
- "name": "欧米茄绝境验证战",
- "difficulty": 100
- },
- {
- "id": 45,
- "name": "幻想龙诗绝境战",
- "difficulty": 100
- },
- {
- "id": 43,
- "name": "绝境战(旧版本)",
- "difficulty": 100
- }
- ];
- const defaultZone = 54;
-
- (function() {
-
- function ProcessLocationIcon(startingIcon,key)
- {
- let parentElement = startingIcon.parentElement.parentElement.parentElement;
-
- let usernameElement = FindUsernameElement(parentElement);
- //console.log(`获取的用户名: ${usernameElement ? usernameElement.innerText : '未找到'}`);
- let server = FindServer(startingIcon);
- //console.log(`获取的服务器: ${server}`);
-
- if (usernameElement && server) {
- InsertLogsIcon(usernameElement, server, key)
- }
- }
-
- function FindUsernameElement(parentElement)
- {
- // 非个人页:第一个能被鼠标点击、仅包含文本的 span 元素
- let elements = parentElement.querySelectorAll('span.cursor');
- //console.log("找到的元素数量(非个人页): ", elements.length);
- for (let element of elements)
- {
- if (element.childNodes.length == 1 && element.innerText.length >= 1 && element.innerText.length <= 6)
- {
- return element;
- }
- }
-
- // 个人页
- elements = parentElement.querySelectorAll('span.ft24.ftw');
- for (let element of elements)
- {
- if (element.childNodes.length == 1 && element.innerText.length >= 1 && element.innerText.length <= 6)
- {
- return element;
- }
- }
-
- return null;
- }
-
- /*
- * 结构 1:
- * <i>
- * <span>
- * <span>区</span>
- * <span>服</span>
- * </span>
- * 结构 2:
- * <i>
- * <span>区 服</span>
- * 结构 3:
- * <i>
- * <span>区</span>
- * <span>服</span>
- */
- function FindServer(startingIcon)
- {
- let element = startingIcon.nextElementSibling;
- if (element && element.querySelector('span'))
- {
- element = element.querySelector('span:first-child');
- }
- let text = element.textContent.trim();
- if (text.includes(' '))
- {
- return text.split(' ')[1];
- }
- else
- {
- return element.nextElementSibling ? element.nextElementSibling.textContent : '';
- }
- }
-
- async function getData(name,server,zoneId){
-
- var difficulty = zones.find((zone) => {
- return zone.id == zoneId
- }).difficulty
-
- var graphqlQuery = `
- {
- characterData {
- character(name: "${name}", serverRegion: "cn", serverSlug: "${server}") {
- zoneRankings(zoneID: ${zoneId}, difficulty: ${difficulty})
- }
- }
- }
- `
-
- try {
- let response = await fetch(url, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json charset=UTF-8',
- 'Authorization': 'Bearer '+ apiToken
- },
- body: JSON.stringify({ query: graphqlQuery }),
- })
- return await response.json();
- } catch (error) {
- console.log('Request Failed', error);
- }
- }
-
- function getRankColor(rank){
- if(rank == '-') return "#666"
- if (rank === 100) return "#e5cc80";
- if (rank >= 99) return "#e268a8";
- if (rank >= 95) return "#ff8000";
- if (rank >= 75) return "#a335ee";
- if (rank >= 50) return "#0070ff";
- if (rank >= 25) return "#1eff00";
- else return "#666";
- }
-
- function getBossUrl(bossId){
- return `https://assets.rpglogs.cn/img/ff/bosses/${bossId}-icon.jpg?v=2`
- }
-
- function getJobIconUrl(jobName){
- return `https://assets.rpglogs.cn/img/ff/icons/${jobName}.png`
- }
-
- function buildBossLogs(boosId,rank,jobName){
- var bossDiv = document.createElement('td');
- var bossNode = document.createElement('img');
- var rankNode = document.createElement('a');
- bossNode.setAttribute('src',getBossUrl(boosId));
- bossNode.style.width = '24px';
- bossNode.style.height = '24px';
- rankNode.innerText = rank?Math.round(rank):'-';;
- rankNode.style.color = getRankColor(rankNode.innerHTML);
- rankNode.style.textAlign = 'center'
- rankNode.style.marginLeft = '10px'
- bossDiv.style.display = 'flex'
- bossDiv.style.justifyContent = 'center'
- bossDiv.style.alignItems = 'center'
- bossDiv.style.textAlign = 'center'
- bossDiv.style.border = '2px solid #333'
-
- bossDiv.append(bossNode);
- bossDiv.append(rankNode);
-
- if(jobName){
- var jobNode = document.createElement('img');
- jobNode.setAttribute('src',getJobIconUrl(jobName));
- jobNode.style.width = '24px';
- jobNode.style.height = '24px';
- jobNode.style.marginLeft = '4px';
- jobNode.style.marginRight = '5px';
- jobNode.style.border = '1px solid #555555';
- bossDiv.append(jobNode);
- }
-
- return bossDiv
- }
-
- async function updateData(usernameElement,charaKey,server,zoneId){
- var data = await getData(usernameElement.innerText,server,zoneId)
- console.log(data)
- var rankings = data?.data?.characterData?.character?.zoneRankings.rankings
- var logsNode = document.getElementById('chara'+charaKey)
- logsNode.style.display = 'flex'
- console.log(rankings)
- logsNode.innerHTML = ''
- rankings?.forEach((ranking) => {
- var node = buildBossLogs(ranking.encounter.id,ranking.rankPercent,ranking.spec)
- logsNode.append(node);
- })
- }
-
- function InsertLogsIcon(usernameElement, server,key)
- {
- var viewerDiv = document.createElement('div')
- var selectNode = document.createElement('select')
- selectNode.setAttribute('id','chara-select'+key)
- selectNode.style.backgroundColor = '#000'
- selectNode.style.color = 'white'
- selectNode.style.border = 'none'
- selectNode.style.outline = 'none'
- selectNode.addEventListener('change', () => {
- console.log(selectNode.options[selectNode.selectedOptions])
- updateData(usernameElement,key,server,selectNode.options[selectNode.selectedIndex].value)
- })
- zones.forEach((zone) => {
- var zoneOption = document.createElement('option')
- zoneOption.text = zone.name
- zoneOption.value = zone.id
- selectNode.add(zoneOption)
- if(zone.id === defaultZone){
- selectNode.selectedIndex = defaultZone
- }
- })
- var logsNode = document.createElement('tr')
- logsNode.setAttribute('id','chara'+key)
- logsNode.style.borderCollapse = 'collapse'
- logsNode.style.borderTop = '2px solid #333'
- logsNode.style.borderBottom = '2px solid #333'
- logsNode.style.backgroundColor = '#000'
- updateData(usernameElement,key,server,defaultZone)
- viewerDiv.style.display = 'flex'
- viewerDiv.append(selectNode)
- viewerDiv.append(logsNode)
-
- var newNode = document.createElement('a');
- var username = usernameElement.innerText;
- newNode.id = 'ff-icon';
- newNode.href = `https://cn.fflogs.com/character/CN/${server}/${username}`;
- newNode.innerHTML = `<img src="https://assets.rpglogs.cn/img/ff/favicon.png" height="30px" width="30px">`;
- newNode.style.backgroundColor = '#000'
- newNode.border = '2px solid #333'
-
- viewerDiv.append(newNode);
-
- console.log(usernameElement.parentElement.parentElement.parentElement.children.length)
- if(usernameElement.parentElement.parentElement.parentElement.children.length == 2){
- usernameElement.parentElement.parentElement.insertAdjacentElement('afterend', viewerDiv);
- }
- else{
- usernameElement.parentElement.insertAdjacentElement('afterend', viewerDiv);
- }
-
-
- console.log(`FFLogs 图标已添加到:${username}@${server}`);
- }
-
- setInterval(function() {
- var elements = document.querySelectorAll('.icon-location.dwcolor'); // 搜索服务器前的图标作为定位特征
-
- elements.forEach(function(iconElement,key) {
- if (!iconElement.hasAttribute('data-logs-processed'))
- {
- ProcessLocationIcon(iconElement,key);
- iconElement.setAttribute('data-logs-processed', 'true'); // 标记已处理
- }
- });
- }, delay);
- })();