您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
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 */ })();