Minor improvements to FFlogs and progression tools.
当前为
// ==UserScript==
// @name FFProgs
// @namespace http://tampermonkey.net/
// @version 0.1.0
// @description Minor improvements to FFlogs and progression tools.
// @author You
// @match https://www.fflogs.com/*
// @icon https://assets.rpglogs.com/img/ff/favicon.png?v=2
// @grant none
// ==/UserScript==
(function () {
if (/(^|\.)fflogs\.com$/.test(document.location.hostname) === false) { return; };
// Helper functions
function elements(arr) {
return arr.map(e => document.getElementById(e));
}
function addGlobalEventListener(type, selector, callaBack) {
document.addEventListener(type, e => {
if (e.target.matches(selector)) callaBack(e);
})
}
function retrieveWindowVariables(variables) {
const ret = {};
let scriptContent = "";
for (let i = 0; i < variables.length; i++) {
const currVariable = variables[i];
scriptContent += `if (typeof ${currVariable} !== \"undefined\") $(\"body\").attr(\"tmp_${currVariable}\", JSON.stringify(${currVariable}));\n`
}
const script = document.createElement("script");
script.id = "tmpScript";
script.appendChild(document.createTextNode(scriptContent));
(document.body || document.head || document.documentElement).appendChild(script);
for (let i = 0; i < variables.length; i++) {
const currVariable = variables[i];
ret[currVariable] = $.parseJSON($("body").attr(`tmp_${currVariable}`));
$("body").removeAttr(`tmp_${currVariable}`);
}
$("#tmpScript").remove();
return ret;
}
// Easter Egg/Credits
const characterName = document.querySelector("#character-name > .character-name-link");
if (characterName) {
if (characterName.innerHTML === "Chad Bradly") {
// GIGACHAD
const characterPortrait = document.getElementById("character-portrait-image");
characterPortrait.src = "https://c.tenor.com/epNMHGvRyHcAAAAd/gigachad-chad.gif";
// Adds background to your own page
const addBackgroundList = ["portrait-and-basics", "character-header-customize-action-box", "update-box"];
elements(addBackgroundList).forEach((e) => {
if (e) {
e.className = "slightly-transparent-box";
}
})
const banner = document.getElementById("character-portrait-box");
if (banner) {
banner.style = "background-image: url(\"https://cdn.discordapp.com/attachments/613521566185029642/925189465868218368/ffxiv_dx11_sH6dfhzjue.jpg\");";
banner.className = "with-banner";
}
}
}
// Adblock
const deleteList = ["top-banner", "bottom-banner", "playwire-video-container", "patron-box", "gear-box-ad"];
elements(deleteList).forEach(e => {
if (e) {
e.outerHTML = "";
}
});
// Removes alt-text from item images.
const imgs = document.getElementsByClassName("gear-img-cell");
for (let i = 0; i < imgs.length; i++) {
const img = imgs[i].firstChild;
if (img) {
img.alt = "";
}
}
// XIVAnalysis button
const tabs = document.getElementById("top-level-view-tabs");
if (tabs) {
function getReportUrl() {
const reportURL = document.location.href.split("/reports/")[1];
const [report, reportInfo] = reportURL.split("#");
let fight, job;
if (reportInfo) {
reportInfo.split("&").forEach((e) => {
const [key, value] = e.split("=")
if (key === "fight") {
fight = value;
}
if (fight && key === "source") {
job = value;
}
})
}
let url = "https://xivanalysis.com/fflogs";
[report, fight, job].forEach((urlElement) => {
if (urlElement) {
url += `/${urlElement}`;
}
});
return url;
}
function refreshAnalysis() {
const xivanalysisButton = document.getElementById("xivanalysis-tab");
const url = getReportUrl();
xivanalysisButton.href = url;
}
const url = getReportUrl();
const xivanalysisButton = document.createElement("a");
xivanalysisButton.href = url;
xivanalysisButton.target = "_blank";
xivanalysisButton.classList.add("big-tab", "view-type-tab");
xivanalysisButton.id = "xivanalysis-tab";
const icon = document.createElement("span");
icon.classList.add("zmdi", "zmdi-time-interval");
xivanalysisButton.appendChild(icon);
const text = document.createElement("span");
text.classList.add("big-tab-text");
text.innerHTML = "<br>xivanalysis";
xivanalysisButton.appendChild(text);
tabs.firstChild.before(xivanalysisButton);
tabs.addEventListener("click", (e) => { refreshAnalysis(); });
}
//Video Player Stuff
const videoButton = document.querySelector(".replay-video");
if (videoButton) {
const streams = {};
videoButton.addEventListener("click", (e) => {
const selectVideoButton = document.getElementById("select-video");
if (selectVideoButton) {
// Functions for the multistream buttons.
const videoFrame = document.getElementById("video-frame-inner");
function showMultistreamFrame() {
const platform = "youTube"
const iframe = document.createElement("iframe");
iframe.id = "player";
iframe.style = "border: none; width:100%; height: 100%;";
iframe.allowFullscreen = "1";
iframe.allow = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture;";
iframe.title = "YouTube video player";
videoFrame.innerHTML = iframe.outerHTML;
}
function showMultistreamOptions() {
const div = document.createElement("div");
div.style = "text-align: center;";
const form = document.createElement("form");
form.style = "margin: 0;";
form.acceptCharset = "utf-8";
form.method = "GET";
form.action = "javascript:void(0);";
const table = document.createElement("table");
table.style = "border-collapse: separate; border-spacing: 8px; margin: auto; text-align: left;";
//Table Infromation
const infoRow = document.createElement("tr");
const nameInfo = document.createElement("td");
const URLInfo = document.createElement("td");
const offsetInfo = document.createElement("td");
nameInfo.innerHTML = "Name:";
URLInfo.innerHTML = "Stream URL:";
offsetInfo.innerHTML = "Offset:";
offsetInfo.style = "max-width: 60px;";
infoRow.append(nameInfo, URLInfo, offsetInfo);
table.appendChild(infoRow);
const raidFrames = document.querySelectorAll(".raid-frame-contents");
const raiders = [];
raidFrames.forEach((frame) => {
raiders.push(frame.innerHTML);
})
raiders.forEach((person) => {
const id = person.replace(/ /g, "_");
const tableRow = document.createElement("tr");
const nameData = document.createElement("td");
nameData.innerHTML = person;
tableRow.appendChild(nameData);
const streamData = document.createElement("td");
const streamUrl = document.createElement("input");
streamUrl.style = "min-width: 260px;"
streamUrl.type = "text";
streamUrl.id = `${id}-stream_url`;
streamUrl.name = `${id}-stream_url`;
streamUrl.placeholder = "youtube.com/watch?v= or twitch.tv/videos/";
if (streams[id] && streams[id].url) {
streamUrl.setAttribute("value", streams[id].url);
}
streamUrl.classList.add("url-table-row");
streamData.appendChild(streamUrl);
tableRow.appendChild(streamData);
const offsetData = document.createElement("td");
const offsetTime = document.createElement("input");
offsetTime.size = "3";
offsetTime.id = `${id}-stream_offset`;
offsetTime.name = `${id}-stream_offset`;
offsetTime.placeholder = "# in sec";
if (streams[id] && streams[id].offset) {
offsetTime.setAttribute("value", streams[id].offset)
}
offsetTime.classList.add("url-table-row");
offsetData.appendChild(offsetTime);
tableRow.appendChild(offsetData);
table.appendChild(tableRow);
})
form.appendChild(table);
div.appendChild(form);
videoFrame.innerHTML = div.outerHTML;
}
addGlobalEventListener("input", ".url-table-row", (e) => {
const [user, action] = e.target.id.split("-");
const value = e.target.value;
if (action === "stream_url") {
if (!streams[user]) streams[user] = {};
streams[user].url = value;
}
if (action === "stream_offset") {
if (!streams[user]) streams[user] = {};
streams[user].offset = value;
}
})
// Creates Menu Below Video Player
const multiStreamOptions = document.getElementById("multistream-options");
if (!multiStreamOptions) {
const videoFrameControls = document.getElementById("video-frame-controls");
const multiStreamO = document.createElement("span");
multiStreamO.style = "float: right; margin-right: 10px;";
multiStreamO.id = "multistream-options";
multiStreamO.classList.add("graph-legend-button");
multiStreamO.onclick = showMultistreamOptions;
multiStreamO.innerText = "Multistream options"
videoFrameControls.appendChild(multiStreamO);
const multiStreamV = document.createElement("span");
multiStreamV.style = "margin-right: -1px; float: right;";
multiStreamV.id = "multistream-view";
multiStreamV.classList.add("graph-legend-button");
multiStreamV.onclick = showMultistreamFrame;
multiStreamV.innerText = "Multistream View";
videoFrameControls.appendChild(multiStreamV);
}
// Save Video URL (OLD)
selectVideoButton.addEventListener("click", (e) => {
const windowVariables = retrieveWindowVariables(["videoID", "videoOffset"]);
if (windowVariables.videoID !== "none") {
const videoURLInput = document.getElementById("video_url");
videoURLInput.value = `https://www.youtube.com/watch?v=${windowVariables.videoID}`;
}
if (windowVariables.videoOffset) {
const videoOffsetInput = document.getElementById("video_offset");
videoOffsetInput.value = windowVariables.videoOffset;
}
})
}
})
}
/*
Backlog:
Make youtube/twitch livestream work
Streams work across multiple fights in one log.
<- Upload to greasy fork here 0.1.0 ->
Multiple POV"s depending on selected player.
Add way to share log viewer and save current streams to a log.
Doing:
Make youtube videos work.
Make Twitch VOD"s work.
Import/export settings
Use my Own I frames
Done:
Save video inputted into video player,
Make settings be able to add streams to players
Save Stream/Offset to session storage on edit for the zones so no need for submit
*/
})();