94list-laravel-tampermonkey

对接 94list-laravel 的油猴脚本

当前为 2024-03-19 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name              94list-laravel-tampermonkey
// @namespace         https://github.com/huankong233/94list-laravel-tampermonkey
// @version           0.0.2
// @author            huan_kong
// @description       对接 94list-laravel 的油猴脚本
// @license           MIT
// @homepage          https://github.com/huankong233/94list-laravel-tampermonkey
// @supportURL        https://github.com/huankong233/94list-laravel-tampermonkey
// @icon              https://huankong.top/favicon.ico
// @match             *://pan.baidu.com/disk/main*
// @match             *://pan.baidu.com/disk/home*
// @match             *://yun.baidu.com/disk/main*
// @match             *://yun.baidu.com/disk/home*
// @connect           localhost
// @connect           127.0.0.1
// @connect           *
// @require           https://registry.npmmirror.com/jquery/3.7.1/files/dist/jquery.min.js
// @require           https://registry.npmmirror.com/sweetalert2/11.10.6/files/dist/sweetalert2.all.min.js
// @grant             GM_xmlhttpRequest
// @grant             GM_addStyle
// @grant             GM_setClipboard
// @grant             GM_registerMenuCommand
// ==/UserScript==

$(async function () {
  GM_registerMenuCommand('⚙️ 设置', () => {
    Swal.fire({
      title: '⚙️ 设置',
      html: `<div>
        <p>94list-laravel-site-url</p>
        <input type="text" id="siteUrl" value=${
          localStorage.getItem('94list-laravel-site-url') ?? ''
        }>
        <p>94list-laravel-site-password</p>
        <input type="text" id="sitePassword" value=${
          localStorage.getItem('94list-laravel-site-password') ?? ''
        }>
        <p>94list-laravel-site-aria2-host</p>
        <input type="text" id="siteAriaHost" value=${
          localStorage.getItem('94list-laravel-site-aria2-host') ?? ''
        }>
        <p>94list-laravel-site-aria2-secret</p>
        <input type="text" id="siteAriaSecret" value=${
          localStorage.getItem('94list-laravel-site-aria2-secret') ?? ''
        }>
      </div>`,
      icon: 'info',
      showConfirmButton: true
    }).then(() => {
      localStorage.setItem('94list-laravel-site-url', document.querySelector('#siteUrl').value)
      localStorage.setItem(
        '94list-laravel-site-password',
        document.querySelector('#sitePassword').value
      )
      localStorage.setItem(
        '94list-laravel-site-aria2-host',
        document.querySelector('#siteAriaHost').value
      )
      localStorage.setItem(
        '94list-laravel-site-aria2-secret',
        document.querySelector('#siteAriaSecret').value
      )
      location.reload()
    })
  })

  function setLocalStorage(key, url) {
    localStorage.setItem(key, url)
    location.reload()
  }

  const request = params => {
    return new Promise((resolve, reject) =>
      GM_xmlhttpRequest({
        ...params,
        onload: res => (res.status === 200 ? resolve(res) : reject(res)),
        onerror: err => reject(err)
      })
    )
  }

  const siteUrl = localStorage.getItem('94list-laravel-site-url')
  const password = localStorage.getItem('94list-laravel-site-password')

  if (!siteUrl | (siteUrl === 'null')) {
    await Swal.fire({
      title: '请先设置 94list-laravel-site-url',
      html: `<input type="text" id="siteUrl">`
    })
    setLocalStorage('94list-laravel-site-url', document.querySelector('#siteUrl').value)
  }

  const serevrConfig = await request({
    method: 'POST',
    url: siteUrl + '/api/user/getConfig',
    responseType: 'json'
  })
    .then(res => res.response.data)
    .catch(_ => {
      Swal.fire({
        icon: 'error',
        title: '系统提示',
        text: '请求服务器失败!'
      }).then(_ => setLocalStorage('94list-laravel-site-url', null))
    })

  if (serevrConfig.havePassword && !password | (password === 'null')) {
    await Swal.fire({
      title: '请先设置 94list-laravel-site-password',
      html: `<input type="text" id="sitePassword">`
    })
    setLocalStorage('94list-laravel-site-password', document.querySelector('#sitePassword').value)
  }

  const getPt = () => {
    if (document.location.href.indexOf('.baidu.com/disk/home')) return 'home'
    if (document.location.href.indexOf('.baidu.com/disk/main') > 0) return 'main'
    return ''
  }
  const pt = getPt()

  GM_addStyle(
    `input{outline-style:none;border:1px solid #c0c4cc;border-radius:5px;width:100%;height:100%;padding:0;padding:10px 15px;box-sizing:border-box}.hk table{width:100%;border-collapse:collapse;margin:25px 0;font-size:.9em;font-family:'Segoe UI',Tahoma,Geneva,Verdana,sans-serif;min-width:400px;box-shadow:0 0 20px rgba(0,0,0,0.15)}.hk thead tr{background-color:#009879;color:#fff;text-align:center;}.hk .line{line-height:60px}.hk th,.hk td{padding:12px 15px;width:138px;height:85px;overflow:overlay;display:inline-block;}.hk tbody tr{border-bottom:1px solid #ddd}.hk tbody tr:nth-of-type(even){background-color:#f3f3f3}.hk td{height:100px;}.hk td.line{line-height:75px;}.homeButton button{display: inline-block;line-height: 1;white-space: nowrap;cursor: pointer;background: #fff;border: 1px solid #dcdfe6;color: #606266;-webkit-appearance: none;text-align: center;-webkit-box-sizing: border-box;box-sizing: border-box;outline: 0;margin: 0;-webkit-transition: .1s;transition: .1s;font-weight: 500;padding: 12px 36px;font-size: 14px;border-radius: 4px;height: 32px;padding: 8px 12px;font-size: 14px;color: #fff;background-color: #ff436a;border-color: #ff436a;border-radius: 3px;text-transform: none;outline: none;border: none;margin-right:none !important;}.homeButton{display: inline-block;}`
  )

  if (pt === 'home') {
    $('.tcuLAu').prepend(
      '<div class="homeButton wp-s-agile-tool-bar__h-group"><button style="margin-right:10px;" id="94listDownBtn" class="u-button nd-file-list-toolbar-action-item is-need-left-sep u-button--primary u-button--default u-button--small is-has-icon  u-button--danger"><i class="iconfont icon-download"></i><span>94list-laravel</span></button></div>'
    )
    GM_addStyle(
      `.hk th,.hk td{width:108px !important;height:60px !important;}.hk td{height:75px !important;}`
    )
  } else if (pt === 'main') {
    $('.wp-s-agile-tool-bar__header.is-header-tool').prepend(
      '<div class="wp-s-agile-tool-bar__h-group"><button style="margin-right:10px;" id="94listDownBtn" class="u-button nd-file-list-toolbar-action-item is-need-left-sep u-button--primary u-button--default u-button--small is-has-icon  u-button--danger"><i class="iconfont icon-download"></i><span>94list-laravel</span></button></div>'
    )
  }

  const match = /"bdstoken":"(\w+)"/.exec($('html').html())
  if (match === null) {
    Swal.fire({
      icon: 'error',
      title: '系统提示',
      text: '未知错误!'
    }).then(_ => location.reload())
  }
  const bdstoken = match[1]

  const getSelectedList = function () {
    if (pt === 'home') {
      return require('system-core:context/context.js').instanceForSystem.list.getSelected()
    } else if (pt === 'main') {
      let mainList = document.querySelector('.nd-main-list')
      if (!mainList) mainList = document.querySelector('.nd-new-main-list')
      return mainList.__vue__.selectedList
    }
  }

  $('#94listDownBtn').on('click', async function () {
    if ($('tr.selected img[src*="ceH8M5EZYnGhnBKRceGqmaZXPPw2xbO+1x"]').length > 0) {
      Swal.fire({
        icon: 'error',
        title: '系统提示',
        text: '不支持文件夹解析'
      })
      return
    }
    const selectedIds = getSelectedList().map(v => v.fs_id)
    if (selectedIds.length === 0) {
      Swal.fire({
        title: '系统提示',
        text: '请选择需要下载的文件',
        icon: 'error'
      })
      return
    }
    function getRangeCode(len = 6) {
      const orgStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
      let returnStr = ''
      for (let i = 0; i < len; i++) {
        returnStr += orgStr.charAt(Math.floor(Math.random() * orgStr.length))
      }
      return returnStr
    }
    Swal.fire({
      title: false,
      text: '服务器请求中',
      showCloseButton: false,
      showCancelButton: false,
      showConfirmButton: false,
      didOpen: () => Swal.showLoading()
    })
    const pwd = getRangeCode(4)
    const shareLink = await $.ajax({
      method: 'post',
      url: `https://pan.baidu.com/share/set?channel=chunlei&bdstoken=${bdstoken}period=1&pwd=${pwd}&eflag_disable=true&channel_list=%5B%5D&schannel=4&fid_list=[${selectedIds}]`
    })
    if (shareLink.show_msg) {
      Swal.fire({
        title: '系统提示',
        text: shareLink.show_msg,
        icon: 'error'
      })
      return
    }
    const url = shareLink.link
    const shareFileList = await request({
      method: 'post',
      url: siteUrl + '/api/user/getFileList',
      headers: {
        'Content-Type': 'application/json'
      },
      data: JSON.stringify({
        dir: '/',
        url,
        pwd,
        password
      }),
      responseType: 'json'
    }).catch(err => {
      Swal.fire({
        icon: 'error',
        title: '系统提示',
        text: err.response.message
      }).then(_ =>
        err.response.message == '密码不匹配'
          ? setLocalStorage('94list-laravel-site-password', null)
          : location.reload()
      )
    })
    const shareSign = await request({
      method: 'post',
      url: siteUrl + '/api/user/getSign',
      headers: {
        'Content-Type': 'application/json'
      },
      data: JSON.stringify({
        uk: shareFileList.response.data.uk,
        shareid: shareFileList.response.data.shareid,
        password
      }),
      responseType: 'json'
    }).catch(err => {
      Swal.fire({
        icon: 'error',
        title: '系统提示',
        text: err.response.message
      }).then(_ =>
        err.response.message == '密码不匹配'
          ? setLocalStorage('94list-laravel-site-password', null)
          : location.reload()
      )
    })
    const downLinks = await request({
      method: 'post',
      url: siteUrl + '/api/user/downloadFiles',
      headers: {
        'Content-Type': 'application/json'
      },
      data: JSON.stringify({
        fs_ids: selectedIds,
        timestamp: shareSign.response.data.timestamp,
        uk: shareFileList.response.data.uk,
        sign: shareSign.response.data.sign,
        randsk: shareFileList.response.data.randsk,
        shareid: shareFileList.response.data.shareid,
        password
      }),
      responseType: 'json'
    }).catch(err => {
      Swal.fire({
        icon: 'error',
        title: '系统提示',
        text: err.response.message
      }).then(_ =>
        err.response.message == '密码不匹配'
          ? setLocalStorage('94list-laravel-site-password', null)
          : location.reload()
      )
    })
    Swal.close()

    Swal.fire({
      html: `<h3>当前下载UA: ${serevrConfig.userAgent}</h3><div class="hk"><table><thead><tr><th class="line">文件名</th><th class="line">地址</th><th class="line">操作</th></tr></thead><tbody></tbody></table></div>`
    })

    downLinks.response.data.forEach(link => {
      $('.swal2-html-container .hk table tbody').append(`
      <tr>
          <td class="line">${link.server_filename}</td>
          <td>${link.dlink}</td>
          <td><button class="aria" data-dlink="${link.dlink}" data-filename="${link.server_filename}">发送到Aria2</button><button class="idm" data-dlink="${link.dlink}" data-filename="${link.server_filename}">尝试调用IDM</button><button class="copy" data-dlink="${link.dlink}">复制链接</button></td>
      </tr>`)
    })

    $('.hk button.aria').on('click', async function () {
      let aria2Host = localStorage.getItem('94list-laravel-site-aria2-host')
      if (!aria2Host || aria2Host === 'null') {
        await Swal.fire({
          title: '请先设置 94list-laravel-site-aria2-host',
          html: `<input type="text" id="siteAriaHost">`
        })

        aria2Host = document.querySelector('#siteAriaHost').value
        localStorage.setItem('94list-laravel-site-aria2-host', aria2Host)
      }

      let aria2Secret = localStorage.getItem('94list-laravel-site-aria2-secret')

      await request({
        method: 'post',
        url: aria2Host,
        headers: {
          'Content-Type': 'application/json'
        },
        data: JSON.stringify({
          jsonrpc: '2.0',
          id: '94list-laravel-tampermonkey',
          method: 'aria2.addUri',
          params: [
            `token:${aria2Secret}`,
            [$(this).data('dlink')],
            {
              out: $(this).data('filename'),
              header: [`User-Agent: ${serevrConfig.userAgent}`]
            }
          ]
        })
      })
    })

    $('.hk button.idm').on('click', async function () {
      const blob = await request({
        method: 'get',
        url: $(this).data('dlink'),
        responseType: 'blob',
        headers: { 'User-Agent': serevrConfig.userAgent }
      })
      const url = URL.createObjectURL(blob)
      const a = document.createElement('a')
      a.href = url
      a.download = $(this).data('filename')
      a.click()
      URL.revokeObjectURL(url)
    })

    $('.hk button.copy').on('click', function () {
      GM_setClipboard($(this).data('dlink'), 'dlink')
    })
  })
})