Steam🎮-100%

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.2
// @match        *store.steampowered.com/app/*
// @include      *igg-games.com/*-free-download.html?cdl*
// @include      *skidrowreloaded.com/*&z123*
// @match        https://online-fix.me/index.php?do=search*
// @run-at       document-end
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addValueChangeListener
// @grant        GM_xmlhttpRequest
// @connect      skidrowreloaded.com
// @connect      online-fix.me
// @license      MIT
// @namespace    DEV314R
// ==/UserScript==

(function() {
 "use strict";

// ---------- labels ----------
 const LABEL_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"
 };
 const LABEL_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"
 };

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=LABEL_DL[langKey]||LABEL_DL.en;
const multiLabel=LABEL_MULTI[langKey]||LABEL_MULTI.en;

// ---------- base utils ----------
const normBase=s=>s.normalize("NFD").replace(/[\u0300-\u036f]|[©®™℠]|\?/g,"").replace(/[:'–—]/g,"").trim().toLowerCase();
const slugify=s=>normBase(s).replace(/\s+/g,"-");
const qEncode=s=>encodeURIComponent(s);

// ---------- platform ----------
const defaultData={IGG:{source:"1Fichier"},Skidrow:{source:"MEGA"},FitGirl:{source:"DataNodes"}};
let platformData=GM_getValue("platformData",defaultData);
let platform=GM_getValue("platform","Skidrow");
if(!platformData[platform])platformData[platform]={source:defaultData[platform].source};
GM_setValue("platformData",platformData);
let sdl=platformData[platform].source;

function setPlatform(p){
 platform=p;
 GM_setValue("platform",platform);
 if(!platformData[platform])platformData[platform]={source:defaultData[platform].source};
 sdl=platformData[platform].source;
 GM_setValue("platformData",platformData);
 renderSourceFlyout();
 updateDownloadLink(true);
}
function setSourceForPlatform(src){
 platformData[platform]={source:src};
 GM_setValue("platformData",platformData);
 sdl=src;
}

// ---------- style ----------
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);

// ---------- gmFetch ----------
const gmFetchHTML=(url,timeout=10000)=>new Promise(resolve=>{
 if(typeof GM_xmlhttpRequest!=="function"){resolve(null);return;}
 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 ----------
let gameNameCache=null;
const ensureGameName=async()=>{
 if(gameNameCache) return gameNameCache;
 const local=document.querySelector('span[itemprop="name"]')?.textContent||document.querySelector("#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;
 let i=0;
 const f=["⠁","⠃","⠇","⠧","⠷","⠿","⠻","⠟","⠯","⠷","⠧","⠇","⠃"];
 stopLoadingAnim(span,"");
 span._timer=setInterval(()=>{span.textContent=f[i=++i%f.length]+" "+dlLabel},90);
}
function stopLoadingAnim(span,txt){
 if(!span)return;
 if(span._timer)clearInterval(span._timer);
 delete span._timer;
 span.textContent=txt;
}

// ---------- skidrow ----------
async function testSkidrowStepByStep(slug,enc){
 if(!slug)return null;
 const q=encodeURIComponent(slug);
 const searchDoc=await gmFetchHTML(`https://www.skidrowreloaded.com/?s=${q}`);
 if(!searchDoc)return null;
 const post=[...searchDoc.querySelectorAll("[class^=post] h2 a[href]")].find(a=>a.textContent.toLowerCase().includes(slug.replace(/-/g," ").toLowerCase()));
 if(!post)return null;
 const postDoc=await gmFetchHTML(post.href);
 if(!postDoc)return null;
 return [...postDoc.querySelectorAll("[id^=tabs] p strong")].find(s=>s.textContent.toLowerCase().includes(enc.toLowerCase()))?.closest("p")?.querySelector("a")?.href||null;
}

// ---------- apply link ----------
let skidrowLinkCache=null;
const applyLink=dl=>{
 if(!dl)return;
 const enc=qEncode(sdl);
 if(platform==="IGG"){
  dl.href=`https://igg-games.com/${gameNameCache}-free-download.html?cdl&src=${enc}`;
  dl.target="_blank";dl.onclick=null;
 }else if(platform==="FitGirl"){
  dl.href=`https://fitgirl-repacks.site/?s=${gameNameCache.replace(/-/g,"+")}&src=${enc}`;
  dl.target="_blank";dl.onclick=null;
 }else{
  dl.href="#";dl.onclick=async e=>{
   e.preventDefault();
   const span=dl.querySelector("span");
   if(skidrowLinkCache){window.open(skidrowLinkCache,"_blank");return;}
   startLoadingAnim(span);
   skidrowLinkCache=await testSkidrowStepByStep(gameNameCache,enc);
   stopLoadingAnim(span,skidrowLinkCache?dlLabel:"❌➡🎯➡🔄");
   if(skidrowLinkCache)window.open(skidrowLinkCache,"_blank");
  };
 }
};

// reset labels
document.addEventListener("click",e=>{
 if(!e.target.closest(".flyout"))return;
 skidrowLinkCache=null;
 document.querySelectorAll(".download-btn span,#add314 span").forEach(s=>s.textContent=dlLabel);
});

// ---------- flyouts ----------
const sourcesByPlatform={
 IGG:["1Fichier","MegaUp.net","Mega.nz","GoFile","Bowfile","Google Drive"],
 Skidrow:["MEGA","1FICHIER","PIXELDRAIN","MEDIAFIRE","GOFILE","VIKINGFILE","BOWFILE","1CLOUDFILE"],
 FitGirl:["DataNodes","FuckingFast","MultiUpload"]
};

function createFlyout(label,key,items,stars=[]){
 const container=document.querySelector("#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;
  if(key==="platform")setPlatform(v);else setSourceForPlatform(v);
  btn.textContent=`${label}: ${v}`;
  updateDownloadLink(true);
 }));
}

function renderSourceFlyout(){
 document.querySelectorAll('.menu[data-type="source"]').forEach(n=>n.remove());
 const container=document.querySelector("#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">🎯: ${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();
  const v=a.dataset.value;
  setSourceForPlatform(v);
  btn.textContent=`🎯: ${v}`;
  updateDownloadLink(true);
 }));
}

// ---------- update DL ----------
const updateDownloadLink=async(force=false)=>{
 const dl=document.querySelector('#add314');if(!dl)return;
 if(!force && !document.hasFocus())return;
 const name=await ensureGameName();if(!name)return;
 applyLink(dl);
};

// ---------- UI init ----------
const initUI=()=>{
 const wrap=document.querySelector('.game_area_purchase_game_wrapper:not(#demoGameBtn) > * > .game_purchase_action');
 if(!wrap||document.querySelector('.game_area_comingsoon,.game_area_bubble'))return;
 if(document.querySelector(".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=document.querySelector("[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);

// Multijoueur check
 const FixGameListInMulti=["slime rancher 2"];
 const raw=document.querySelector("#appHubAppName")?.innerText||"";
 const norm=raw.normalize("NFD").replace(/[\u0300-\u036f]|[\u00A9\u00AE\u2122\u2120]/g,"").replace(/:| :|'| -|\?|\./g,"").trim();
 const q=norm.replace(/[\\/\s]+/g,"+");

 if((document.querySelector(".game_area_details_specs_ctn[href*='category2=3']:is([href*='6'],[href*='8'],[href*='9'])")||!FixGameListInMulti.includes(norm.toLowerCase())) && raw){
  const url=`https://online-fix.me/index.php?do=search&subaction=search&story=${q}`;
  GM_xmlhttpRequest({
   method:"GET",url,
   onload:r=>{
    if(r.status!==200)return;
    const doc=new DOMParser().parseFromString(r.responseText,"text/html");
    const titles=[...doc.querySelectorAll("h2.title")].map(el=>el.innerText.replace(/ по сети/g,"").toLowerCase());
    if(!titles.some(t=>t.includes(norm.toLowerCase())))return;
    const base=document.querySelector("#add314");
    if(base)base.insertAdjacentHTML("afterend",`<a id="add314r" class="btn_green_steamui btn_medium" href="${url}" target="_blank"><span>${multiLabel}</span></a>`);
   }
  });
 }
};

// ---------- SPA observe ----------
const observer=new MutationObserver(()=>{if(document.querySelector('.game_area_purchase_game_wrapper'))initUI();});
observer.observe(document.documentElement,{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=()=>{
  document.querySelectorAll("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 redirect ----------
if(/online-fix.me\/index.php\?do=search/i.test(location.href)){
 const titles=document.querySelectorAll('h2.title');
 if(titles.length===1)titles[0].click();
}

})();