Steam -100% with semi-auto-download for IGG
当前为
// ==UserScript==
// @name Steam🎮-100%
// @name:ar ستيم 🎮-100%
// @name:bg Steam🎮-100%
// @name:cs Steam🎮-100%
// @name:da Steam🎮-100%
// @name:de Steam🎮-100%
// @name:el Steam🎮-100%
// @name:en Steam🎮-100%
// @name:es Steam🎮-100%
// @name:fi Steam🎮-100%
// @name:fr Steam🎮-100%
// @name:fr-CA Steam🎮-100%
// @name:he סטים 🎮-100%
// @name:hu Steam🎮-100%
// @name:id Steam🎮-100%
// @name:it Steam🎮-100%
// @name:ja スチーム🎮-100%
// @name:ko 스팀🎮-100%
// @name:nl Steam🎮-100%
// @name:no Steam🎮-100%
// @name:pl Steam🎮-100%
// @name:pt Steam🎮-100%
// @name:ro Steam🎮-100%
// @name:ru Steam🎮-100%
// @name:sk Steam🎮-100%
// @name:sv Steam🎮-100%
// @name:th สตีม🎮-100%
// @name:tr Steam🎮-100%
// @name:uk Steam🎮-100%
// @name:vi Steam🎮-100%
// @name:zh Steam🎮-100%
// @description Steam -100% with semi-auto-download for IGG
// @description:ar ستيم -100٪ مع تحميل شبه تلقائي لـ IGG
// @description:bg Steam -100% със полуавтоматично изтегляне за IGG
// @description:cs Steam -100% s poloautomatickým stahováním pro IGG
// @description:da Steam -100% med semi-automatisk download til IGG
// @description:de Steam -100% mit halbautomatischem Download für IGG
// @description:el Steam -100% με ημι-αυτόματη λήψη για IGG
// @description:en Steam -100% with semi-auto-download for IGG
// @description:es Steam -100% con descarga semi-automática para IGG
// @description:fi Steam -100% puoliautomaattisella latauksella IGG:lle
// @description:fr Steam -100% avec semi-téléchargement automatique pour IGG
// @description:fr-CA Steam -100% avec semi-téléchargement automatique pour IGG
// @description:he Steam -100% עם הורדה חצי-אוטומטית עבור IGG
// @description:hu Steam -100% félautomatikus letöltéssel IGG-hez
// @description:id Steam -100% dengan unduhan semi-otomatis untuk IGG
// @description:it Steam -100% con download semi-automatico per IGG
// @description:ja Steam -100%:IGG用の半自動ダウンロード対応
// @description:ko Steam -100% IGG용 반자동 다운로드 지원
// @description:nl Steam -100% met semi-automatische download voor IGG
// @description:no Steam -100% med semi-automatisk nedlasting for IGG
// @description:pl Steam -100% z półautomatycznym pobieraniem dla IGG
// @description:pt Steam -100% com semi-download automático para IGG
// @description:ro Steam -100% cu descărcare semi-automată pentru IGG
// @description:ru Steam -100% с полуавтоматической загрузкой для IGG
// @description:sk Steam -100% s poloautomatickým sťahovaním pre IGG
// @description:sv Steam -100% med semi-automatisk nedladdning för IGG
// @description:th Steam -100% พร้อมการดาวน์โหลดกึ่งอัตโนมัติสำหรับ IGG
// @description:tr Steam -100% IGG için yarı otomatik indirme ile
// @description:uk Steam -100% з напівавтоматичним завантаженням для IGG
// @description:vi Steam -100% với tải xuống bán tự động cho IGG
// @description:zh Steam -100%,支持 IGG 半自动下载
// @version 1.1.6
// @match *store.steampowered.com/app/*
// @include *igg-games.com/*-free-download.html?cdl*
// @match https://online-fix.me/games/*
// @run-at document-end
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addValueChangeListener
// @grant GM_xmlhttpRequest
// @connect skidrowreloaded.com
// @connect fitgirl-repacks.site
// @connect online-fix.me
// @license MIT
// @namespace DEV314R
// ==/UserScript==
(function() {
"use strict";
// ---------- Utils DOM ----------
const $ = s => document.querySelector(s);
const $$ = s => [...document.querySelectorAll(s)];
// ---------- Labels ----------
const LABELS = {
dl: { en:"Download",ar:"تحميل",bg:"Изтегли",
"zh-CN":"下载","zh-TW":"下載",
cs:"Stáhnout",da:"Download",nl:"Downloaden",
fi:"Lataa", fr:"Télécharger",de:"Herunterladen",
el:"Λήψη",hu:"Letöltés", id:"Unduh",
it:"Scarica",ja:"ダウンロード",ko:"다운로드",
no:"Last ned",pl:"Pobierz",
"pt-PT":"Transferir","pt-BR":"Baixar",
ro:"Descărcare", ru:"Скачать",
"es-ES":"Descargar","es-LA":"Bajar",
sv:"Ladda ner", th:"ดาวน์โหลด", tr:"İndir",
uk:"Завантажити", vi:"Tải xuống"},
multi: {en:"Multiplayer",ar:"متعدد اللاعبين",bg:"Мултиплейър",
"zh-CN":"多人游戏","zh-TW":"多人遊戲",
cs:"Multiplayer",da:"Flerspiller", nl:"Multiplayer",
fi:"Moninpeli",fr:"Multijoueur",de:"Mehrspieler",
el:"Πολλαπλών παικτών", hu:"Többjátékos",id:"Multipemain",
it:"Multigiocatore",ja:"マルチプレイヤー",ko:"멀티플레이어",
no:"Flerspiller",pl:"Wieloosобowy",
"pt-PT":"Multijogador","pt-BR":"Multijogador",
ro:"Multiplayer",ru:"Многопользовательская игра",
"es-ES":"Multijugador","es-LA":"Multijugador",
sv:"Flerspelarläge",th:"ผู้เล่นหลายคน", tr:"Çok Oyunculu",
uk:"Багатокористувацька",vi:"Nhiều người chơi"},
source: { en:"Source",ar:"المصدر",bg:"Източник",
"zh-CN":"来源","zh-TW":"來源",
cs:"Zdroj",da:"Kilde",nl:"Bron",
fi:"Lähde",fr:"Source",de:"Quelle",
el:"Πηγή",hu:"Forrás",id:"Sumber",
it:"Fonte",ja:"ソース",ko:"출처",
no:"Kilde",pl:"Źródło",
"pt-PT":"Fonte","pt-BR":"Fonte",
ro:"Sursă",ru:"Источник",
"es-ES":"Fuente","es-LA":"Fuente",
sv:"Källa",th:"แหล่งที่มา",tr:"Kaynak",
uk:"Джерело",vi:"Nguồn"},
unavailable: { en:"unavailable",ar:"غير متوفر",bg:"Недостъпно",
"zh-CN":"不可用","zh-TW":"不可用",
cs:"Nedostupné",da:"Ikke tilgængelig",nl:"Niet beschikbaar",
fi:"Ei saatavilla",fr:"indisponible",de:"Nicht verfügbar",
el:"Μη διαθέσιμο",hu:"Nem elérhető",id:"Tidak tersedia",
it:"Non disponibile",ja:"利用不可",ko:"사용 불가",
no:"Utilgjengelig",pl:"Niedostępne",
"pt-PT":"Indisponível","pt-BR":"Indisponível",
ro:"Indisponibil",ru:"Недоступно",
"es-ES":"No disponible","es-LA":"No disponible",
sv:"Inte tillgängligt",th:"ไม่พร้อมใช้งาน",tr:"Mevcut değil",
uk:"Недоступно",vi:"Không khả dụng" }
};
const lang = navigator.language.toLowerCase();
const langKey = (() => {
if(lang.startsWith("pt-br")) return "pt-BR";
if(lang.startsWith("pt-pt")) return "pt-PT";
if(lang.startsWith("zh-tw")||lang.startsWith("zh-hk")) return "zh-TW";
if(lang.startsWith("zh")) return "zh-CN";
if(lang.startsWith("es-")) return ["es-mx","es-ar","es-co","es-cl","es-pe","es-ve","es-uy","es-bo","es-py","es-cr","es-pa","es-do","es-ec","es-gt","es-hn","es-ni","es-sv","es-pr","es-419"].includes(lang) ? "es-LA" : "es-ES";
return lang.split("-")[0];
})();
const dlLabel = LABELS.dl[langKey]||LABELS.dl.en;
const multiLabel = LABELS.multi[langKey]||LABELS.multi.en;
const sourceLabel = LABELS.source[langKey]||LABELS.source.en;
const unavailableLabel = LABELS.unavailable[langKey]||LABELS.unavailable.en;
// ---------- Base utils ----------
const norm = s => s.normalize("NFD").replace(/[\u0300-\u036f]|[©®™℠]|\?/g,"").replace(/[:'–—]/g,"").trim().toLowerCase();
const slugify = s => norm(s)//.replace(/\s+/g,"-");
// ---------- Platform ----------
const defaultData = { IGG:{source:"1Fichier"}, Skidrow:{source:"MEGA"}, FitGirl:{source:"DataNodes"} };
let platformData = GM_getValue("platformData", defaultData);
let platform = GM_getValue("platform", "Skidrow");
platformData[platform] ||= { source: defaultData[platform].source };
GM_setValue("platformData", platformData);
let sdl = platformData[platform].source;
function setPlatform(p){
platform = p;
GM_setValue("platform", p);
platformData[p] ||= { source: defaultData[p].source };
sdl = platformData[p].source;
GM_setValue("platformData", platformData);
renderSourceFlyout();
updateDownloadLink(true);
}
function setSourceForPlatform(src){
platformData[platform].source = src;
GM_setValue("platformData", platformData);
sdl = src;
}
// ---------- Styles ----------
const style = document.createElement("style");
style.textContent = `
.menu{font-family:Arial,sans-serif;font-size:1em;position:relative;user-select:none;padding:.1em;display:inline-flex}
.menu-btn{background:#67c1f533;color:#67c1f5;padding:.4em .6em;border-radius:.3em;cursor:pointer}
.menu-btn:hover{background:#67c1f5bb;color:#fff}
.flyout{border:none;border-radius:.3em;background:#23262E;position:absolute;top:100%;left:0;display:none;z-index:10000}
.menu:hover .flyout{display:block}
.flyout a{display:block;padding:.4em .6em;background:#23262E;color:#ddd;text-decoration:none}
.flyout a:hover{background:#85949d59;color:#fff}
.menu-container{right:.75em;top:.75em;z-index:9999;position:fixed}`;
document.head.appendChild(style);
// ---------- GM fetch ----------
const gmFetchHTML = (url,timeout=10000) => new Promise(resolve=>{
if(typeof GM_xmlhttpRequest !== "function") return resolve(null);
let done = false;
const timer = setTimeout(()=>{if(!done){done=true; resolve(null);}}, timeout);
GM_xmlhttpRequest({
method: "GET",
url,
onload: r => { if(!done){ done=true; clearTimeout(timer); resolve(new DOMParser().parseFromString(r.responseText,"text/html")); } },
onerror: ()=>{ if(!done){ done=true; clearTimeout(timer); resolve(null); } }
});
});
// ---------- Game Name Cache ----------
let gameNameCache = null;
let gameNameFetched = false;
const ensureGameName = () => gameNameCache;
const fetchGameNameIfNeeded = async () => {
if(gameNameFetched) return gameNameCache;
gameNameFetched = true;
const local = $('span[itemprop="name"]')?.textContent || $("#appHubAppName")?.innerText || "";
if(local) { gameNameCache = slugify(local); return gameNameCache; }
const doc = await gmFetchHTML(location.origin + location.pathname + "?l=english");
const name = doc?.querySelector('span[itemprop="name"]')?.textContent || "";
gameNameCache = name ? slugify(name) : null;
return gameNameCache;
};
// ---------- Spinner ----------
function startLoadingAnim(span){
if(!span) return;
const f=["⠁","⠃","⠇","⠧","⠷","⠿","⠻","⠟","⠯","⠷","⠧","⠇","⠃"];
stopLoadingAnim(span,"");
let i=0;
span._timer = setInterval(()=>{span.textContent=f[i=++i%f.length]+" "+dlLabel;},90);
}
function stopLoadingAnim(span,txt){
if(!span) return;
clearInterval(span._timer);
delete span._timer;
span.textContent = txt;
}
// ---------- Step By Step ----------
const skidrowLinkCache = new Map();
async function SkidrowStep(slug, enc){
if(!slug) return "🐞❎";
const cacheKey = slug + "::" + enc.toLowerCase();
if(skidrowLinkCache.has(cacheKey)) return skidrowLinkCache.get(cacheKey);
const q = slug;
const searchDoc = await gmFetchHTML(`https://www.skidrowreloaded.com/?s=${encodeURIComponent(q)}`);
if(!searchDoc) return "🐞❎";
const slugNorm = slug.replace(/-/g," ").normalize("NFD").replace(/(\s|-)?[^A-Za-z0-9\s]/gi, "").toLowerCase();
const encNorm = enc.toLowerCase();
const post = [...searchDoc.querySelectorAll("[class^=post] h2 a[href]")]
.find(a => a.textContent.toLowerCase().includes(slugNorm));
if(!post) return "❌ "+unavailableLabel;
const postDoc = await gmFetchHTML(post.href);
if(!postDoc) return "🐞❎";
const link = [...postDoc.querySelectorAll("[id^=tabs] p strong")]
.find(s => s.textContent.toLowerCase().includes(encNorm))
?.closest("p")?.querySelector("a[href]")?.href || null;
const result = link || sourceLabel+" "+unavailableLabel;
skidrowLinkCache.set(cacheKey, result);
return result;
}
async function FitGirlStep(slug,enc){
if(!slug) return "🐞❎";
const searchDoc = await gmFetchHTML(`https://fitgirl-repacks.site/${slug}`);
if(!searchDoc) return "🐞❎";
const encNorm = enc.replace(/Filehoster: /g,"").toLowerCase();
const link = [...searchDoc.querySelectorAll(".entry-content > ul > li > a[href]")]
.find(a=>a.textContent.toLowerCase().includes(encNorm))?.href || null;
return link || "❌ "+unavailableLabel;
}
// ---------- Apply Link ----------
let LinkCache = null;
function applyLink(dl){
if(!dl) return;
const enc = sdl;
if(platform==="IGG"){
dl.href=`https://igg-games.com/${gameNameCache.replace(/(\s|-)?[^A-Za-z0-9\s]/gi, "").replace(/\s/gi,"-")}-free-download.html?cdl&src=${enc}`;
dl.target="_blank"; dl.onclick=null;
} else {
dl.href="#";
dl.onclick = async e=>{
e.preventDefault();
const span = dl.querySelector("span");
if(LinkCache && !LinkCache.startsWith("❎") && !LinkCache.startsWith("❌")){
window.open(LinkCache,"_blank"); return;
}
startLoadingAnim(span);
LinkCache = platform==="FitGirl" ? await FitGirlStep(gameNameCache.replace(/(\s|-)?[^A-Za-z0-9\s]/gi, "").replace(/\s/gi,"-"),enc) : await SkidrowStep(gameNameCache,enc);
stopLoadingAnim(span, LinkCache.startsWith("http") ? dlLabel : LinkCache);
if(LinkCache.startsWith("http")) window.open(LinkCache,"_blank");
};
}
}
// ---------- Reset labels ----------
document.addEventListener("click", e=>{
if(!e.target.closest(".flyout")) return;
LinkCache=null;
$$("span#add314, .download-btn span").forEach(s=>s.textContent=dlLabel);
});
// ---------- Flyouts ----------
const sourcesByPlatform = {
IGG:["1Fichier","MegaUp.net","Mega.nz","GoFile","MixDrop","Rapidgator","Bowfile","SendCM","Google Drive"],
Skidrow:["MEGA","1FICHIER","PIXELDRAIN","MEDIAFIRE","GOFILE","VIKINGFILE","BOWFILE","1CLOUDFILE","MEGAUP","MULTI LINKS","TORRENT"],
FitGirl:["DataNodes","FuckingFast","MultiUpload","1337x","magnet",".torrent file only","RuTor","magnet","Tapochek.net"]
};
function createFlyout(label,key,items,stars=[]){
const container=$("#category_block"); if(!container) return;
const val = key==="platform"? platform : sdl;
const div=document.createElement("div");
div.className="menu"; div.dataset.type=key;
div.innerHTML=`<div class="menu-btn">${label}: ${val}</div><div class="flyout">${items.map(i=>`<a href="#" data-value="${i}">${stars.includes(i)?"⭐"+i:i}</a>`).join("")}</div>`;
container.insertAdjacentElement("beforebegin",div);
const btn = div.querySelector(".menu-btn");
div.querySelectorAll("a").forEach(a=>a.addEventListener("click", e=>{
e.preventDefault();
const v=a.dataset.value;
key==="platform" ? setPlatform(v) : setSourceForPlatform(v);
btn.textContent=`${label}: ${v}`;
updateDownloadLink(true);
}));
}
function renderSourceFlyout(){
$$('.menu[data-type="source"]').forEach(n=>n.remove());
const container=$("#category_block"); if(!container) return;
const list = sourcesByPlatform[platform]||[];
const val = platformData[platform]?.source||defaultData[platform].source||list[0];
GM_setValue("platformData",platformData);
const div=document.createElement("div");
div.className="menu"; div.dataset.type="source";
div.innerHTML=`<div class="menu-btn">${sourceLabel}: ${val}</div><div class="flyout">${list.map(i=>`<a href="#" data-value="${i}">${i}</a>`).join("")}</div>`;
container.insertAdjacentElement("beforebegin",div);
const btn=div.querySelector(".menu-btn");
div.querySelectorAll("a").forEach(a=>a.addEventListener("click", e=>{
e.preventDefault();
setSourceForPlatform(a.dataset.value);
btn.textContent=`${sourceLabel}: ${a.dataset.value}`;
updateDownloadLink(true);
}));
}
// ---------- Update DL ----------
const updateDownloadLink=async(force=false)=>{
const dl=$("#add314"); if(!dl) return;
if(!force && !document.hasFocus()) return;
if(!gameNameCache) await fetchGameNameIfNeeded();
if(!gameNameCache) return;
applyLink(dl);
};
// ---------- Multijoueur bouton ----------
const createMultiButton=async()=>{
const FixGameSet=new Set(["slime rancher 2"]);
const slug=await fetchGameNameIfNeeded();
if(!slug) return;
const norm=slug.replace(/-/g," ").normalize("NFD").replace(/[\u0300-\u036f\u00A9\u00AE\u2122\u2120]/g,"").trim().toLowerCase();
const q=norm.replace(/[\\/\s]+/g,"+");
if(!(document.querySelector(".game_area_details_specs_ctn[href*='category2=3']:is([href*='6'],[href*='8'],[href*='9'])")||!FixGameSet.has(norm))) return;
if($("#add314r") ) return;
const url=`https://online-fix.me/index.php?do=search&subaction=search&story=${q}`;
const doc=await gmFetchHTML(url,10000);
if(!doc) return;
const hit=[...doc.querySelectorAll(".article")].map(a=>{
const h2=a.querySelector("h2.title");
if(!h2) return null;
const raw=h2.innerText.replace(/ по сети/gi,"");
const title=raw.normalize("NFD").replace(/[\u0300-\u036f\u00A9\u00AE\u2122\u2120]/g,"").trim().toLowerCase();
const link=a.querySelector("a.big-link")?.href||a.querySelector("a.img")?.href||h2.closest("a")?.href||null;
return title===norm&&link?link:null;
}).filter(Boolean)[0];
if(!hit) return;
const base=$("#add314");
if(!base) return;
base.insertAdjacentHTML("afterend",`<a id="add314r" class="btn_green_steamui btn_medium" href="${hit}" target="_blank"><span>${multiLabel}</span></a>`);
};
// ---------- UI init ----------
const initUI=()=>{
const wrap=$('.game_area_purchase_game_wrapper:not(#demoGameBtn) > * > .game_purchase_action');
if(!wrap||$('.game_area_comingsoon,.game_area_bubble')) return;
if($(".menu-container")) return;
const cont=document.createElement("div"); cont.className="menu-container"; document.body.appendChild(cont);
createFlyout("🌐","platform",["IGG","Skidrow","FitGirl"],["IGG","Skidrow"]);
renderSourceFlyout();
const priceEl=$("[class^='discount_original_price'],[data-price-final]");
const price=(priceEl?.innerText?.trim())||"";
const finalPrice = price?`0,--${price.slice(-1)}`:"0,00";
wrap.innerHTML=`
<div class="game_purchase_action_bg">
<div class="discount_block game_purchase_discount" data-discount="100">
<div class="discount_pct">-100%</div>
<div class="discount_prices">
<div class="discount_original_price">${price}</div>
<div class="discount_final_price">${finalPrice}</div>
</div>
</div>
<div class="btn_addtocart">
<a id="add314" class="btn_green_steamui btn_medium" href="#" target="_blank"><span>${dlLabel}</span></a>
</div>
</div>`;
updateDownloadLink(true);
createMultiButton();
};
// ---------- SPA observe ----------
const observer = new MutationObserver(()=>{ if($('.game_area_purchase_game_wrapper')) initUI(); });
const target = $('#appMountPoint') || document.documentElement;
observer.observe(target,{ childList:true, subtree:true });
initUI();
// ---------- IGG auto DL ----------
if(/igg-games.+download\.html\?cdl/i.test(location.href)){
document.title="⏳"+document.title;
const temp=6000;
const tryDownload=()=>{
$$("b.uk-heading-bullet").forEach(el=>{
if(el.innerText.replace(/Link\s*:?/i,"").includes(sdl)){
const links=el.parentElement.querySelectorAll("a[href]");
let i=0;
const open=()=>{if(i<links.length){links[i++].click();setTimeout(open,temp);}else setTimeout(()=>window.close(),2000);};
open();
}
});
};
tryDownload();
}
// ---------- Online-Fix auto-translate ----------
if(location.hostname.includes("online-fix.me")){
const lang = navigator.language.split("-")[0];
const applyTranslate = () => {
const sel = document.querySelector(".goog-te-combo");
if(!sel) return false;
sel.value = lang;
sel.dispatchEvent(new Event("change"));
return true;
};
const t = setInterval(() => { if(applyTranslate()) clearInterval(t); }, 300);
document.addEventListener("DOMContentLoaded", applyTranslate);
}
})();