Modrinthify Spigot

Redirect spigotmc.org mod pages to modrinth.com when possible

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name        Modrinthify Spigot
// @namespace   Violentmonkey Scripts
// @match       *://*.spigotmc.org/*
// @grant       none
// @version     1.4.1.2
// @author      devBoi76
// @license     MIT
// @description Redirect spigotmc.org mod pages to modrinth.com when possible
// ==/UserScript==

/* jshint esversion: 6 */

function similarity(s1, s2) {
	var longer = s1;
	var shorter = s2;
	if (s1.length < s2.length) {
	  longer = s2;
	  shorter = s1;
	}
	var longerLength = longer.length;
	if (longerLength == 0) {
	  return 1.0;
	}
	return (longerLength - editDistance(longer, shorter)) / parseFloat(longerLength);
  }
  
function editDistance(s1, s2) {
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();

var costs = new Array();
for (var i = 0; i <= s1.length; i++) {
	var lastValue = i;
	for (var j = 0; j <= s2.length; j++) {
	if (i == 0)
		costs[j] = j;
	else {
		if (j > 0) {
		var newValue = costs[j - 1];
		if (s1.charAt(i - 1) != s2.charAt(j - 1))
			newValue = Math.min(Math.min(newValue, lastValue),
			costs[j]) + 1;
		costs[j - 1] = lastValue;
		lastValue = newValue;
		}
	}
	}
	if (i > 0)
	costs[s2.length] = lastValue;
}
return costs[s2.length];
}

const svg = '<svg class="h-full absolute" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 777 141.73" aria-hidden="true" class="text-logo"><g><path d="M159.07,89.29A70.94,70.94,0,1,0,20,63.52H32A58.78,58.78,0,0,1,145.23,49.93l-11.66,3.12a46.54,46.54,0,0,0-29-26.52l-2.15,12.13a34.31,34.31,0,0,1,2.77,63.26l3.19,11.9a46.52,46.52,0,0,0,28.33-49l11.62-3.1A57.94,57.94,0,0,1,147.27,85Z" transform="translate(-19.79)" fill="var(--color-brand)" fill-rule="evenodd"></path><path transform="translate(-19.79)" fill="var(--color-brand)" d="M108.92,139.3A70.93,70.93,0,0,1,19.79,76h12a59.48,59.48,0,0,0,1.78,9.91,58.73,58.73,0,0,0,3.63,9.91l10.68-6.41a46.58,46.58,0,0,1,44.72-65L90.43,36.54A34.38,34.38,0,0,0,57.36,79.75C57.67,80.88,58,82,58.43,83l13.66-8.19L68,63.93l12.9-13.25,16.31-3.51L101.9,53l-7.52,7.61-6.55,2.06-4.69,4.82,2.3,6.38s4.64,4.94,4.65,4.94l6.57-1.74,4.67-5.13,10.2-3.24,3,6.84L104.05,88.43,86.41,94l-7.92-8.81L64.7,93.48a34.44,34.44,0,0,0,28.72,11.59L96.61,117A46.6,46.6,0,0,1,54.13,99.83l-10.64,6.38a58.81,58.81,0,0,0,99.6-9.77l11.8,4.29A70.77,70.77,0,0,1,108.92,139.3Z"></path></g></svg>'

const HTML = `
<div id="modrinthify-redirect" class="button" style="background-color: #30B27B;\
border-top-right-radius: 0;\
border-bottom-right-radius: 0;\
font-weight: 600;"\
 data-tooltip="Get on Modrinth">\
<figure class="icon icon-margin relative w-5 h-4" >\
${svg}
</figure> \
Get on Modrinth\
</div>  \
`

const DONATE_HTML = `\
<a target="_blank" href="REDIRECT" class="" style="background-color: #FF5E5B;border-top-left-radius: 0;border-bottom-left-radius: 0;font-weight: 600;display: inline-flex;padding: 4px;font-weight: 600;box-sizing: border-box !important;color: white;width: fit-content;flex-grow: 0;height: 100%;text-decoration: none; padding-right: 10px;" data-tooltip="Support the Author"> <div style="display: inline-block;height: auto;width: 28px;"><img src="https://i.ibb.co/Y2Xgd4Q/kofilogo.png" style="height: 100%;"></div>Support the Author
</a>
`

const REGEX = /[\(\[](forge|fabric|forge\/fabric|fabric\/forge|unused|deprecated)[\)\]]/gmi
PLUGIN_PAGE_HTML = `<style>#modrinth-body {
    overflow: hidden;
    display: inline-block;
    height: 32px;
    color: black;
    box-sizing: border-box !important;
    vertical-align: middle;
    font-size: 18px;
    margin: 0.5rem 0;
    width: min-content;
    border-radius: 0.5rem;
    transition: background-color, 0.2s;
  }\
  #modrinth-body:hover {
    text-decoration: none;
    background: #FAFAFA;
  }</style> \
  <a id="modrinth-body" href="MR_HREF" target="_blank" class="" style="  "><div style="display: flex;/*! font-size: 18px; */box-sizing: border-box !important;width: max-content;height: 32px;"><img style="display:inline-block; box-sizing: border-box !important;flex-grow: 0;height: 100%;" src="MR_ICON"><div class="" style="display: inline-block;padding: 7px 0.5rem 7px !important;border-block: 1px solid #d9d9d9;padding: 0;font-weight: 600;line-height: 18px;box-sizing: border-box !important;flex-grow: 0;">MR_NAME</div><div class="" style="display: inline-flex;padding: 4px;font-weight: 600;box-sizing: border-box !important;background: #30B27B;color: white;width: fit-content;flex-grow: 0;height: 100%;"><div style="display: inline-block;height: auto;width: 32px;"><svg class="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 777 141.73" aria-hidden="true" style="fill: currentColor; height: 100%;"><g><path d="M159.07,89.29A70.94,70.94,0,1,0,20,63.52H32A58.78,58.78,0,0,1,145.23,49.93l-11.66,3.12a46.54,46.54,0,0,0-29-26.52l-2.15,12.13a34.31,34.31,0,0,1,2.77,63.26l3.19,11.9a46.52,46.52,0,0,0,28.33-49l11.62-3.1A57.94,57.94,0,0,1,147.27,85Z" transform="translate(-19.79)" fill="var(--color-brand)" fill-rule="evenodd"></path><path transform="translate(-19.79)" fill="var(--color-brand)" d="M108.92,139.3A70.93,70.93,0,0,1,19.79,76h12a59.48,59.48,0,0,0,1.78,9.91,58.73,58.73,0,0,0,3.63,9.91l10.68-6.41a46.58,46.58,0,0,1,44.72-65L90.43,36.54A34.38,34.38,0,0,0,57.36,79.75C57.67,80.88,58,82,58.43,83l13.66-8.19L68,63.93l12.9-13.25,16.31-3.51L101.9,53l-7.52,7.61-6.55,2.06-4.69,4.82,2.3,6.38s4.64,4.94,4.65,4.94l6.57-1.74,4.67-5.13,10.2-3.24,3,6.84L104.05,88.43,86.41,94l-7.92-8.81L64.7,93.48a34.44,34.44,0,0,0,28.72,11.59L96.61,117A46.6,46.6,0,0,1,54.13,99.83l-10.64,6.38a58.81,58.81,0,0,0,99.6-9.77l11.8,4.29A70.77,70.77,0,0,1,108.92,139.3Z"></path></g></svg></div>
  <div style="margin-right: 5px;">
Get on Modrinth
</div>
</div></div></a>`

const SEARCH_PAGE_HTML = `<a href="REDIRECT" target="_blank" class="box flex" style="overflow: hidden"><div>\
<img style="display:inline-block; height: 3rem" src="ICON_SOURCE">\
<div class="mx-2 font-bold" style="display: inline-block">MOD_NAME</div>\
<div style="display: inline-block">BUTTON_HTML</div></div></a>`

function main() {
    const api_facets = `facets=[["categories:'bukkit'","categories:'spigot'","categories:'paper'","categories:'purpur'","categories:'sponge'","categories:'bungeecord'","categories:'waterfall'","categories:'velocity'"],["project_type:mod"]]`
    
    const url = document.URL.split("/")

    let is_search = false
    let is_project_page = false
    if (url[3] == "search") {
        is_search = true
    } else if (url[3] == "resources") {
        is_project_page = true
    } else return

    let query = ""
    if (is_search) {
        query = document.querySelector(".titleBar > h1:nth-child(1)").textContent.match(/Search Results for Query: (.*)/)[1]
    
    } else if (is_project_page) {
        query = document.querySelector(".resourceInfo > h1:nth-child(3)").firstChild.textContent
    }

    fetch(`https://api.modrinth.com/v2/search?limit=3&query=${query}&${api_facets}`, {method: "GET", mode: "cors"})
        .then(response => response.json())
        .then(resp => {
            
            if (resp.hits.length == 0) {
                return
            }
            
            let max_sim = 0
            let max_hit = undefined
    
        for (const hit of resp.hits) {
            if (similarity(hit.title.trim(), query) > max_sim) {
                max_sim = similarity(hit.title.trim(), query)
                max_hit = hit
            }
        }
        if (max_sim <= 0.7) {
            return
        }

        if (is_search) {
			let s = document.querySelector("div.pageNavLinkGroup:nth-child(2)")
            let div = document.createElement("div")
            div.outerHTML = s.innerHTML = PLUGIN_PAGE_HTML
			.replace("MR_ICON", max_hit.icon_url)
			.replace("MR_NAME", max_hit.title.trim())
			.replace("MR_HREF", `https://modrinth.com/${max_hit.project_type}/${max_hit.slug}`)
			.replace("BUTTON_HTML", HTML) + s.innerHTML

			s.after(div)
			
		} else if (is_project_page) {
			let s = document.querySelector(".innerContent")

			s.innerHTML = PLUGIN_PAGE_HTML
			.replace("MR_ICON", max_hit.icon_url)
			.replace("MR_NAME", max_hit.title.trim())
			.replace("MR_HREF", `https://modrinth.com/${max_hit.project_type}/${max_hit.slug}`)
			.replace("BUTTON_HTML", HTML) + s.innerHTML
		}

        fetch(`https://api.modrinth.com/v2/project/${max_hit.slug}`, {method: "GET", mode: "cors"})
		.then(response_p => response_p.json())
		.then(resp_p => {
			if (resp_p.donation_urls.length > 0) {
                document.querySelector("#modrinth-body div").innerHTML += DONATE_HTML.replace("REDIRECT", resp_p.donation_urls[0].url)
				// if (!is_search) {
				// 	redir.parentNode.parentNode.parentNode.style.marginRight = "-150px"
				// }
			}
		})

           
    })


}

main()