98tang一键推送下载到115与115cookie登录

根据98tang特定元素插入按钮并一键推送下载到115与115cookie登录,支持bot与web下载

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         98tang一键推送下载到115与115cookie登录
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  根据98tang特定元素插入按钮并一键推送下载到115与115cookie登录,支持bot与web下载
// @author       yelc668
// @match        *://*.115.com/*
// @include      https://www.sehuatang.*
// @include      https://www.weterytrtrr.*
// @include      https://www.qweqwtret.*
// @include      https://www.retreytryuyt.*
// @include      https://www.qwerwrrt.*
// @include      https://www.5aylp.*
// @include      https://www.jq2t4.*
// @include      https://www.0krgb.*
// @include      https://www.1qyqs.*
// @include      https://www.ds5hk.*
// @include      https://sehuatang.*
// @include      https://weterytrtrr.*
// @include      https://qweqwtret.*
// @include      https://retreytryuyt.*
// @include      https://qwerwrrt.*
// @include      https://5aylp.*
// @include      https://jq2t4.*
// @include      https://1qyqs.*
// @include      https://ds5hk.*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @grant        GM_notification
// @grant        GM_cookie
// @grant        GM_setClipboard
// ==/UserScript==

;(function () {
  const config = {
    webDownloadFolderId: GM_getValue('webDownloadFolderId', ''),
    botDownloadUrl: GM_getValue('botDownloadUrl', ''),
    signUrl: 'https://115.com/?ct=offline&ac=space&_=', // 获取115 token签名接口
    addTaskUrl: 'https://115.com/web/lixian/?ct=lixian&ac=add_task_url', // 添加115离线任务接口
    addTaskUrls: 'https://115.com/web/lixian/?ct=lixian&ac=add_task_urls', // 添加115b多个离线任务接口
    getUserUrl: 'https://webapi.115.com/offine/downpath', // 获取115用户userid接口
  }
  let requireCookieNames = ['UID', 'CID', 'SEID']

  function findLinksAndCreateButtons() {
    const blockcode = document.querySelector('.blockcode')
    let links = []
    if (blockcode) {
      const codes = blockcode.querySelectorAll('[id*="code_"]')
      codes.forEach((code) => {
        const textContent = code.textContent
        const magnetLinks = textContent.match(/magnet:\S+/g)
        const ed2kLinks = textContent.match(/ed2k:\/\/\|file\|.*?\|[0-9]+\|[A-Fa-f0-9]+\|\//g)
        if (magnetLinks) {
          links = links.concat(magnetLinks)
        }
        if (ed2kLinks) {
          links = links.concat(ed2kLinks)
        }
      })
      if (links.length !== 0) {
        createSettingButton()
        const em = blockcode.querySelector('em')
        if (em) {
          if (config.webDownloadFolderId) {
            const webDownloadTrigger = createButton('Web下载', () => handleLinks(links, addWebTorrents))
            em.parentNode.insertBefore(webDownloadTrigger, em.nextSibling)
          }
          if (config.botDownloadUrl) {
            const botDownloadTrigger = createButton('Bot下载', () => handleLinks(links, addBotTorrents))
            em.parentNode.insertBefore(botDownloadTrigger, em.nextSibling)
          }
        }
      }
    }
  }
  // 添加bot离线下载任务
  function addBotTorrents(urls) {
    return new Promise((resolve, reject) => {
      try {
        //判断一下botDownloadUrl是否是以http或者https开头
        if (!/^(http|https):\/\/.+(\/)?$/i.test(config.botDownloadUrl)) {
          reject('115bot下载地址格式不正确')
          return
        }
        const url = (config.botDownloadUrl.endsWith('/') ? config.botDownloadUrl : config.botDownloadUrl + '/') + 'ghs/addTaskUrls'
        let formdata = new FormData()
        formdata.append('urls', JSON.stringify(urls))
        GM_xmlhttpRequest({
          method: 'POST',
          url: url,
          data: formdata,
          onload: (responseDetails) => {
            console.log(responseDetails)
            if (responseDetails.status === 200) {
              return responseDetails.responseText.includes('成功') ? resolve('添加' + responseDetails.responseText) : reject(responseDetails.responseText)
            }
            return reject('请检查bot下载地址是否正确')
          },
          error: () => {
            reject(' 请检查bot下载地址是否正确')
          },
        })
      } catch (err) {
        reject(' 请检查bot下载地址是否正确')
      }
    })
  }
  // 添加115web离线任务
  function addWebTorrents(urls) {
    return new Promise((resolve, reject) => {
      const timeout = new Date().getTime()

      const fetchUserIDAndAddTorrents = () => {
        GM_xmlhttpRequest({
          method: 'GET',
          url: config.getUserUrl,
          onload: (responseDetails) => {
            let resData
            try {
              resData = JSON.parse(responseDetails.response)
            } catch (error) {
              reject('获取115用户信息失败: 无效的JSON数据')
              return
            }
            if (!resData.state) {
              reject('获取115用户信息失败')
              return
            }
            const userID = resData.data && resData.data[0] ? resData.data[0].user_id : null
            if (!userID) {
              reject('获取115用户信息失败: 用户ID未找到')
              return
            }
            GM_setValue('X_userID', userID)
            addTorrents(userID)
          },
          onerror: () => reject('获取用户信息失败'),
        })
      }

      const addTorrents = (userID) => {
        GM_xmlhttpRequest({
          method: 'GET',
          url: config.signUrl + timeout,
          onload: (responseDetails) => {
            if (responseDetails.responseText.indexOf('html') >= 0) {
              reject('还没有登录115')
              return
            }
            let signData
            try {
              signData = JSON.parse(responseDetails.response)
            } catch (error) {
              reject('获取签名失败: 无效的JSON数据')
              return
            }
            const { sign } = signData
            let falseUrl = urls.length === 1 ? true : false
            let encodedUrls = falseUrl ? `url=${encodeURIComponent(urls[0])}` : urls.map((url, index) => `url[${index}]=${encodeURIComponent(url)}`).join('&')
            const url = falseUrl ? config.addTaskUrl : config.addTaskUrls
            const addConfig = {
              method: 'POST',
              url: url,
              data: `${encodedUrls}&savepath=&wp_path_id=${config.webDownloadFolderId}&uid=${userID}&sign=${sign}&time=${timeout}`,
              headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
              onload: (res) => {
                let resData
                try {
                  resData = JSON.parse(res.response)
                } catch (error) {
                  reject('添加任务失败: 无效的JSON数据')
                  return
                }
                if (!falseUrl) {
                  if (resData.state === false) return reject(resData.error_msg || '添加任务失败')
                  const notifications = resData.result.map((item, index) => {
                    if (item.state === true) {
                      return `添加成功!索引:${index}`
                    } else {
                      return `添加失败:${item.error_msg || '未知错误'}`
                    }
                  })
                  resolve(notifications)
                } else {
                  if (resData.state === false) {
                    reject(resData.error_msg || '添加任务失败')
                  } else {
                    resolve('添加成功')
                  }
                }
              },
              onerror: () => reject('请求添加离线任务失败'),
            }
            GM_xmlhttpRequest(addConfig)
          },
          onerror: () => reject('获取签名失败'),
        })
      }

      let X_userID = GM_getValue('X_userID', '')
      if (!X_userID) {
        fetchUserIDAndAddTorrents()
      } else {
        addTorrents(X_userID)
      }
    })
  }
  // 色花推送
  function customNotify(message) {
    var ntcwin = document.getElementById('ntcwin')
    var customNtcwin = document.getElementById('customNtcwin')
    var appendParent = document.getElementById('append_parent')
    if (!ntcwin) {
      if (!appendParent) {
        console.error('append_parent element not found.')
        return
      }
      ntcwin = document.createElement('div')
      ntcwin.id = 'ntcwin'
      ntcwin.className = 'ntcwin'
      ntcwin.setAttribute('initialized', 'true')
      ntcwin.style.cssText = 'position: fixed; z-index: 501; left: 50%; top: 117px; display: none; transform: translateX(-50%);'
      ntcwin.innerHTML = `
          <table cellspacing="0" cellpadding="0" class="popupcredit">
              <tbody>
                  <tr>
                      <td class="pc_l">&nbsp;</td>
                      <td class="pc_c"><div class="pc_inner"></div></td>
                      <td class="pc_r">&nbsp;</td>
                  </tr>
              </tbody>
          </table>
      `
      appendParent.appendChild(ntcwin)
    }
    if (!customNtcwin) {
      customNtcwin = document.createElement('div')
      customNtcwin.id = 'customNtcwin'
      customNtcwin.className = 'customNtcwin'
      customNtcwin.style.cssText =
        'position: fixed; z-index: 501; left: 50%; top: 168px; display: none; transform: translateX(-50%); background-color: #f9f9f9; border: 1px solid #ccc; padding: 10px; border-radius: 10px; box-shadow: 0 0 10px rgba(0,0,0,0.1); font-family: Arial, sans-serif; font-size: 14px; line-height: 1.5;'
      appendParent.appendChild(customNtcwin)
    }
    if (Array.isArray(message)) {
      customNtcwin.innerHTML = ''
      message.forEach((msg) => {
        var messageElement = document.createElement('div')
        messageElement.textContent = msg
        customNtcwin.appendChild(messageElement)
      })
      customNtcwin.style.display = 'block'
      setTimeout(function () {
        customNtcwin.style.display = 'none'
      }, 2500)
    } else {
      var pc_inner = ntcwin.querySelector('.pc_inner')
      if (pc_inner) {
        pc_inner.innerHTML = ''
      } else {
        console.error('pc_inner element not found.')
        return
      }
      var messageElement = document.createElement('div')
      messageElement.textContent = message
      pc_inner.appendChild(messageElement)
      ntcwin.style.display = 'block'
      setTimeout(function () {
        ntcwin.style.display = 'none'
      }, 2500)
    }
  }

  // 处理磁力链接的函数
  function handleLinks(links, addUrlFunction) {
    addUrlFunction(links)
      .then((res) => {
        customNotify(res)
      })
      .catch((error) => {
        customNotify('添加链接失败: ' + error)
      })
  }
  // 创建样式按钮的函数
  function createStyledButton(text) {
    const button = document.createElement('button')
    button.textContent = text
    button.style.padding = '10px'
    button.style.border = 'none'
    button.style.borderRadius = '5px'
    button.style.backgroundColor = '#d42f2f'
    button.style.color = 'white'
    button.style.marginRight = '10px'
    button.style.cursor = 'pointer'
    button.style.fontSize = '16px'
    button.onmouseover = function () {
      this.style.backgroundColor = '#db2a3a'
    }
    button.onmouseout = function () {
      this.style.backgroundColor = '#d42f2f'
    }
    return button
  }

  // 创建按钮的函数
  function createButton(text, onClick) {
    const button = document.createElement('em')
    button.textContent = text
    button.style.cssText = 'cursor: pointer; margin-left: 10px;'
    button.addEventListener('click', onClick)
    return button
  }

  // 创建设置按钮
  function createSettingButton() {
    const buttonContainer = document.createElement('div')
    buttonContainer.style.cssText = 'position: fixed; bottom: 20px; right: 20px; z-index: 1000;'
    document.body.appendChild(buttonContainer)
    ;['web设置', 'bot设置'].forEach((type) => {
      const button = createStyledButton(type)
      button.addEventListener('click', () => handleSetting(type))
      buttonContainer.appendChild(button)
    })
  }

  // 处理设置操作
  function handleSetting(type) {
    let promptText, settingKey
    if (type === 'web设置') {
      promptText = '请输入115文件夹ID:'
      settingKey = 'webDownloadFolderId'
    } else {
      promptText = '请输入下载URL:http(s)://'
      settingKey = 'botDownloadUrl'
    }
    const inputValue = prompt(promptText, config[settingKey])
    if (inputValue !== null) {
      GM_setValue(settingKey, inputValue)
      setTimeout(() => window.location.reload(), 2000)
    }
  }

  // <- ---------------------------------------------------------------------------------------------------------------------------------------------------- ->
  // 115 cookie登录 这里更新Gloduck的脚本 他写的115的cookie登录
  /**
   * Alter展示Cookie
   */
  function showCookie() {
    // 使用GM_cookie函数获取Cookie
    GM_cookie.list({ domain: '.115.com' }, function (cookieInfos, error) {
      if (!error) {
        let cookieOutputs = []
        cookieInfos.forEach(function (cookieInfo) {
          if (requireCookieNames.includes(cookieInfo.name)) {
            cookieOutputs.push(`${cookieInfo.name}=${cookieInfo.value}`)
          }
        })
        alert(`Cookie信息为:\n---------------------------\n${cookieOutputs.join('\n')}\n---------------------------\n内容已复制到剪切板!`)
        GM_setClipboard(`${cookieOutputs.join(';')};`)
      } else {
        alert('获取cookie失败,请检查是否支持GM_cookie函数(目前只有beta版支持)')
      }
    })
  }

  /**
   * 初始化复制Cookie按钮
   */
  function initCopyCookieButton() {
    let btnGroupDiv = document.querySelector('div.left-tvf[rel="left_tvf"]')
    if (btnGroupDiv) {
      // 创建复制 Cookie 按钮
      let copyButton = document.createElement('a')
      copyButton.href = 'javascript:;'
      copyButton.className = 'button btn-line btn-upload'
      copyButton.innerHTML = '<i class="icon-operate ifo-copy"></i><span>复制Cookie</span>'

      // 点击显示Cookie
      copyButton.addEventListener('click', showCookie)

      btnGroupDiv.appendChild(copyButton)
    }
  }

  /**
   * 获取Cookie需要的列
   * @param requireFields {Array}
   * @param cookie {string}
   * @returns {Map<any, any>}
   */
  function getRequireFieldFromCookie(requireFields, cookie) {
    let resMap = new Map()
    if (!cookie) {
      return resMap
    }
    let cookies = cookie.split(';')
    cookies.forEach(function (cookie) {
      if (!cookie) {
        return
      }
      let kv = cookie.split('=')
      if (kv.length != 2) {
        return
      }
      if (requireFields.includes(kv[0])) {
        resMap.set(kv[0], kv[1])
      }
    })
    return resMap
  }

  /**
   * Cookie登录
   * @param requireCookieMap {Map}
   * @param validDuration {number}
   */
  function handleCookieLogin(requireCookieMap, validDuration) {
    requireCookieMap.forEach((value, key) => {
      GM_cookie.delete({ name: key }, function (error) {
        if (error) {
          alert(`清除Cookie:[${key}]失败!请检查是否支持GM_cookie函数(目前只有beta版支持)`)
        }
      })
      GM_cookie.set(
        {
          // url: '.115.com',
          name: key,
          value: value,
          domain: '.115.com',
          path: '/',
          secure: false,
          httpOnly: false,
          expirationDate: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * validDuration, // Expires in 30 days
        },
        function (error) {
          if (error) {
            alert(`设置Cookie:[${key}]失败,值为:[${value}]!请检查是否支持GM_cookie函数(目前只有beta版支持)`)
          }
        }
      )
    })
    setTimeout(function () {
      location.reload()
    }, 1000)
  }

  /**
   * 显示Cookie登录的输入框
   */
  function showCookieLoginInputDialog() {
    let inputCookie = prompt('请输入 Cookie:')
    let requireCookieMap = getRequireFieldFromCookie(requireCookieNames, inputCookie)
    if (requireCookieMap.size != requireCookieNames.length) {
      alert(`输入的Cookie需包含[${requireCookieNames.join(',')}],请重新输入!`)
      return
    }
    let defaultValidDuration = 30
    let inputValidDuration = prompt('请输入Cookie有效天数:', defaultValidDuration)
    let validDuration = parseInt(inputValidDuration, 10) || defaultValidDuration
    handleCookieLogin(requireCookieMap, validDuration)
  }

  /**
   * 初始化Cookie登录按钮
   */
  function initCookieLoginButton() {
    let loginFooter = document.querySelector('div.login-footer[rel="login_footer"]')
    if (loginFooter) {
      // 分隔符
      let splitField = document.createElement('i')
      splitField.textContent = '|'
      // 登录按钮
      let loginSpan = document.createElement('span')
      let loginButton = document.createElement('a')
      loginButton.textContent = '使用 Cookie 登录'
      loginButton.href = 'javascript:;'
      loginButton.addEventListener('click', showCookieLoginInputDialog)
      loginSpan.appendChild(loginButton)
      loginFooter.insertBefore(splitField, loginFooter.firstElementChild)
      loginFooter.insertBefore(loginButton, loginFooter.firstElementChild)
    }
  }
  findLinksAndCreateButtons()
  initCookieLoginButton()
  initCopyCookieButton()
})()