Greasy Fork is available in English.

IG-Add2Lib

indiegala 快速领取免费游戏

// ==UserScript==
// @name               IG-Add2Lib
// @namespace          IG-Add2Lib
// @version            1.1.0
// @description        indiegala 快速领取免费游戏
// @author             HCLonely
// @license            MIT
// @iconURL            https://auto-task-test.hclonely.com/img/favicon.ico
// @homepage           https://github.com/HCLonely/IG-Helper/
// @supportURL         https://github.com/HCLonely/IG-Helper/issues/

// @include            *://keylol.com/*
// @include            *://www.indiegala.com/*

// @grant              GM_addStyle
// @grant              GM_xmlhttpRequest
// @grant              GM_registerMenuCommand
// @grant              GM_cookie
// @grant              unsafeWindow

// @require            https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.slim.min.js
// @require            https://cdn.jsdelivr.net/npm/regenerator-runtime@0.13.7/runtime.min.js
// @require            https://cdn.jsdelivr.net/npm/sweetalert2@9
// @require            https://cdn.jsdelivr.net/npm/promise-polyfill@8.1.3/dist/polyfill.min.js
// @require            https://greasyfork.org/scripts/418102-tm-request/code/TM_request.js?version=902218
// @connect            indiegala.com
// @run-at             document-end
// @noframes
// ==/UserScript==

/* global addToIndiegalaLibrary, syncIgLib */
(function () {
  if (window.location.host === 'www.indiegala.com') {
    return;
  }
  function addButton () {
    for (const el of $('a[href*=".indiegala.com/"]:not(".ig-add2lib")')) {
      const $this = $(el).addClass('ig-add2lib')
      const href = $this.attr('href')
      if (/^https?:\/\/.+?\.indiegala\.com\/.+$/.test(href) && !['/login', '/library'].includes(new URL(href).pathname)) {
        $this.after(`<a class="add-to-library" href="javascript:void(0)" onclick="addToIndiegalaLibrary(this)" data-href="${href}" target="_self">入库</a>`)
      }
    }
  }
  unsafeWindow.addToIndiegalaLibrary = async function (el) {
    const href = typeof el === 'string' ? el : $(el).attr('data-href')
    Swal.fire({
      title: '正在获取入库链接...',
      text: href,
      icon: 'info'
    })
    const [url, csrf_token] = await TM_request({
      url: href,
      method: 'GET',
      anonymous: false,
      timeout: 30000,
      retry: 3
    })
      .then(response => {
        if (!response.responseText) {
          console.error(response)
          return null
        }
        const pageId = response.responseText.match(/dataToSend\.(gala_page_)?id[\s]*?=[\s]*?'(.*?)';/)?.[2]
        if (!pageId) {
          console.error(response)
          return null
        }
        const csrf_token = response.responseText.match(/<input name="csrfmiddlewaretoken".+?value="(.+?)"/)?.[1]
        return [new URL(`/developers/ajax/add-to-library/${pageId}/${new URL(href).pathname.replace(/\//g, '')}/${new URL(href).hostname.replace('.indiegala.com', '')}`, href).href, csrf_token]
      })
      .catch(error => {
        console.error(error)
        return null
      })
    if (!url || !csrf_token) {
      Swal.update({
        title: '获取入库链接失败!',
        text: href,
        icon: 'error'
      })
      return null
    }
    Swal.update({
      title: '正在入库...',
      text: href,
      icon: 'info'
    })
    return TM_request({
      url,
      method: 'POST',
      responseType: 'json',
      nocache: true,
      headers: {
        'content-type': 'application/json',
        "X-CSRF-Token": csrf_token
      },
      timeout: 30000,
      retry: 3
    })
      .then(response => {
        if (response.response?.status === 'ok') {
          Swal.update({
            title: '入库成功!',
            text: href,
            icon: 'success'
          })
          if (syncIgLib) {
            syncIgLib(false, false).then(allGames => {
              for (const el of $('a[href*=".indiegala.com/"]')) {
                const $this = $(el).addClass('ig-checked')
                const href = $this.attr('href')
                if (/^https?:\/\/[\w\d]+?\.indiegala\.com\/.+$/.test(href) && allGames.includes(new URL(href).pathname.replace(/\//g, ''))) {
                  $this.addClass('ig-owned')
                }
              }
            })
          }
          return true
        } else if (response.response?.status === 'added') {
          Swal.update({
            title: '已在库中!',
            text: href,
            icon: 'warning'
          })
          return true
        } else if (response.response?.status === 'login' || response.response?.status === 'auth') {
          Swal.fire({
            title: '请先登录!',
            icon: 'error',
            showCancelButton: true,
            confirmButtonText: '登录',
            cancelButtonText: '关闭'
          }).then(({ value }) => {
            if (value) {
              window.open('https://www.indiegala.com/login', '_blank')
            }
          })
          return false
        } else {
          console.error(response)
          Swal.update({
            title: '入库失败!',
            text: href,
            icon: 'error'
          })
          return null
        }
      })
  }
  GM_registerMenuCommand('入库所有', async () => {
    const links = $.makeArray($('a.add-to-library')).map((e, i) => {
      return $(e).prev().hasClass('ig-owned') ? null : $(e).attr('data-href')
    }).filter(e => e)
    const newLinks = [...new Set(links)]
    const failedLinks = []
    for (const link of newLinks) {
      const result = await addToIndiegalaLibrary(link)
      if (result === false) {
        break
      } else if (!result) {
        failedLinks.push(`<a href="${link}" target=_blank">${link}</a>`)
      }
    }
    if (failedLinks.length === 0) {
      Swal.fire({
        title: '全部任务完成!',
        icon: 'success'
      })
    } else {
      Swal.fire({
        title: '以下任务未完成!',
        icon: 'warning',
        html: failedLinks.join('<br/>')
      })
    }
  })
  function getCookies() {
    return new Promise((resolve, reject) => {
      GM_cookie.list({ url: 'https://www.indiegala.com/library/showcase/1' }, function (cookies, error) {
        if (!error) {
          resolve(cookies.map((c) => `${c.name}=${c.value}`).join(';'));
        } else {
          reject(error);
        }
      });
    });
  }
  GM_addStyle('.add-to-library{margin-left:10px;}')
  addButton()
  const observer = new MutationObserver(addButton)
  observer.observe(document.documentElement, {
    attributes: true,
    characterData: true,
    childList: true,
    subtree: true
  })
})()