Greasy Fork 支持简体中文。

pikpak助手

pikpak网盘助手,绕过ip限制,支持aria2下载!

目前為 2022-09-25 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name pikpak助手
  3. // @name:zh-CN pikpak助手
  4. // @namespace http://tampermonkey.net/
  5. // @version 0.6
  6. // @description pikpak网盘助手,绕过ip限制,支持aria2下载!
  7. // @description:zh-CN pikpak网盘助手,绕过ip限制,支持aria2下载!
  8. // @author xiaoziguys
  9. // @match https://mypikpak.com/*
  10. // @icon https://www.google.com/s2/favicons?sz=64&domain=mypikpak.com
  11. // @grant unsafeWindow
  12. // @grant GM_xmlhttpRequest
  13. // @run-at document-start
  14. // @license MIT
  15. // ==/UserScript==
  16. function getPlatform () {
  17. let u = navigator.userAgent;
  18. let isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //判断是否是 android终端
  19. let isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //判断是否是 iOS终端
  20. if(isAndroid){
  21. return 'Android';
  22. }else if(isIOS){
  23. return 'IOS';
  24. }else{
  25. return 'PC';
  26. }
  27. }
  28. function Toast(dom, value) {
  29. dom.innerText = value
  30. dom.style.visibility = 'visible'
  31. setTimeout(() => {dom.style.visibility = 'hidden'}, 1000)
  32. }
  33. function addStyle(id, tag, css) {
  34. tag = tag || 'style';
  35. let doc = document, styleDom = doc.getElementById(id);
  36. if (styleDom) return;
  37. let style = doc.createElement(tag);
  38. style.rel = 'stylesheet';
  39. style.id = id;
  40. tag === 'style' ? style.innerHTML = css : style.href = css;
  41. doc.getElementsByTagName('head')[0].appendChild(style);
  42. }
  43. function post(url, data, headers, type) {
  44. console.log(url, data, headers, type)
  45. data = JSON.stringify(data);
  46. return new Promise((resolve, reject) => {
  47. GM_xmlhttpRequest({
  48. method: "POST", url, headers, data,
  49. responseType: type || 'json',
  50. onload: (res) => {
  51. type === 'blob' ? resolve(res) : resolve(res.response || res.responseText);
  52. },
  53. onerror: (err) => {
  54. reject(err);
  55. },
  56. });
  57. });
  58. }
  59. async function postData(url = '', data = {}, customHeaders = {}, method = 'GET') {
  60. // Default options are marked with *
  61. let options = {
  62. method: method, // *GET, POST, PUT, DELETE, etc.
  63. mode: 'cors', // no-cors, *cors, same-origin
  64. cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
  65. credentials: 'same-origin', // include, *same-origin, omit
  66. headers: {
  67. 'Content-Type': 'application/json',
  68. // 'Content-Type': 'application/x-www-form-urlencoded',
  69. ...customHeaders
  70. },
  71. redirect: 'follow', // manual, *follow, error
  72. referrerPolicy: 'no-referrer'
  73. }
  74. if (method === 'GET') {
  75. const response = await fetch(url, {
  76. method: 'GET', // *GET, POST, PUT, DELETE, etc.
  77. mode: 'cors', // no-cors, *cors, same-origin
  78. cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
  79. credentials: 'same-origin', // include, *same-origin, omit
  80. headers: {
  81. 'Content-Type': 'application/json',
  82. // 'Content-Type': 'application/x-www-form-urlencoded',
  83. ...customHeaders
  84. },
  85. redirect: 'follow', // manual, *follow, error
  86. referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
  87. });
  88. return response.json(); // parses JSON response into native JavaScript objects
  89. } else {
  90. return new Promise((resolve, reject) => {
  91. let xhr = new XMLHttpRequest();
  92. xhr.onreadystatechange = function () {
  93. if (xhr.readyState === 4) {
  94. if (xhr.status === 200) {
  95. resolve(JSON.parse(xhr.response))
  96. } else {
  97. reject({})
  98. }
  99. }
  100. }
  101. xhr.open(method, url) // 带参数
  102. xhr.setRequestHeader('content-type', 'application/json')// 设置服务端要求的参数类型,后面会专门出一期,针对各种常用content-type讲解
  103. xhr.send(JSON.stringify(data));// 带上复杂参数
  104. })
  105. }
  106. }
  107.  
  108. (function() {
  109. 'use strict';
  110. // divert region limit
  111. document.cookie = "pp_access_to_visit=true"
  112. let flag = setInterval(() => {
  113. let container = document.getElementsByClassName('context-menu')
  114. if (container[0]) {
  115. clearInterval(flag)
  116. // ready
  117. let ariaHost = window.localStorage.getItem('ariaHost') || ''
  118. let ariaPath = window.localStorage.getItem('ariaPath') || ''
  119. let ariaToken = window.localStorage.getItem('ariaToken') || ''
  120. // add download btn
  121. let aria2Btn = document.createElement('button')
  122. aria2Btn.innerText = '推送到aria2'
  123. aria2Btn.className = 'el-button el-button--primary'
  124. aria2Btn.style.marginTop = '10px'
  125. container[0].append(aria2Btn)
  126. // aria2配置dom
  127. let btnBox = document.getElementsByClassName('add-resources')[0]
  128. let configBtn = document.createElement('button')
  129. configBtn.innerText = '配置aira2'
  130. configBtn.className = 'el-button el-button--primary aria-config-btn'
  131. configBtn.style.marginTop = '10px'
  132. btnBox.append(configBtn)
  133. // form
  134. let form = document.createElement('div')
  135. form.id = 'aria2form'
  136. addStyle('','',`
  137. #aria2form {
  138. top: 20vh;
  139. position: fixed;
  140. background: #fff;
  141. left: 50%;
  142. width: 320px;
  143. transform: translate(-50%, 0);
  144. padding: 20px;
  145. box-shadow: 0 2px 8px rgb(0 0 0 / 10%);;
  146. border-radius: 4px;
  147. visibility: hidden;
  148. }
  149. .xz-input {
  150. border: #d9d9d9 1px solid;
  151. margin-bottom: 10px;
  152. padding: 5px;
  153. margin-top: 5px;
  154. }
  155. #aria2Toast {
  156. top: 5vh;
  157. position: fixed;
  158. background: #fff;
  159. left: 50%;
  160. transform: translate(-50%, 0);
  161. /* height: 30px; */
  162. padding: 20px;
  163. box-shadow: 0 2px 8px rgb(0 0 0 / 10%);;
  164. border-radius: 4px;
  165. visibility: hidden;
  166. }
  167. @media screen and (max-width: 760px) {
  168. .add-resources .aria-config-btn {
  169. margin-top: 0px!important;
  170. margin-left: 10px;
  171. }
  172. }
  173. `)
  174. document.body.append(form)
  175. form.innerHTML = `
  176. 服务器:<br/>
  177. <div class="el-input xz-input"><input class="el-input__inner" id="aria2Host"></input></div>
  178. 路径:<br/>
  179. <div class="el-input xz-input"><input class="el-input__inner" id="aria2path"></input></div>
  180. 密钥:<br/>
  181. <div class="el-input xz-input"><input class="el-input__inner" id="aria2Token"></input></div>
  182. <button class="el-button el-button--primary" id="ariaSaveBtn">保存</button>
  183. <button class="el-button" id="ariaCancelBtn">取消</button>
  184. `
  185. //toast
  186. let toast = document.createElement('div')
  187. toast.id = 'aria2Toast'
  188. document.body.append(toast)
  189. // 配置aria2
  190. let ariaSaveBtn = document.getElementById('ariaSaveBtn')
  191. let ariaCancelBtn = document.getElementById('ariaCancelBtn')
  192. let ariaInput = document.getElementById('aria2Host')
  193. let ariaPathInput = document.getElementById('aria2path')
  194. let ariaTokenInput = document.getElementById('aria2Token')
  195. ariaInput.value = ariaHost
  196. ariaPathInput.value = ariaPath
  197. ariaTokenInput.value = ariaToken
  198. configBtn.addEventListener('click', () => {
  199. form.style.visibility = 'visible'
  200. })
  201. ariaSaveBtn.addEventListener('click', () => {
  202. form.style.visibility = 'visible'
  203. window.localStorage.setItem('ariaHost',ariaInput.value)
  204. window.localStorage.setItem('ariaPath',ariaPathInput.value)
  205. window.localStorage.setItem('ariaToken',ariaTokenInput.value)
  206. ariaHost = ariaInput.value || ''
  207. ariaPath = ariaPathInput.value || ''
  208. ariaToken = ariaTokenInput.value || ''
  209. Toast(toast, '配置成功')
  210. form.style.visibility = 'hidden'
  211. })
  212. ariaCancelBtn.addEventListener('click', () => {
  213. form.style.visibility = 'hidden'
  214. })
  215. // token
  216. let token = ''
  217. let captcha = ''
  218. for (let i = 0; i < 10; i++) {
  219. let key = window.localStorage.key(i)
  220. if (key && key.startsWith('credentials')) {
  221. let tokenData = JSON.parse(window.localStorage.getItem(key))
  222. token = tokenData.token_type + ' ' + tokenData.access_token
  223. continue
  224. }
  225. if (key && key.startsWith('captcha')) {
  226. let tokenData = JSON.parse(window.localStorage.getItem(key))
  227. captcha = tokenData.token
  228. }
  229. }
  230. let header = {
  231. Authorization: token,
  232. 'x-device-id': window.localStorage.getItem('deviceid'),
  233. 'x-captcha-token': captcha
  234. }
  235. // push to aria2
  236. aria2Btn.addEventListener('click', async () => {
  237. if (!ariaHost) {
  238. Toast(toast, '请先配置aria2')
  239. return
  240. }
  241. let item = document.getElementsByClassName('selected')[0]
  242. let id = item.getAttribute('id')
  243. try {
  244. let res = await postData('https://api-drive.mypikpak.com/drive/v1/files/' + id + '?',{},header)
  245. let ariaData = {
  246. id: new Date().getTime(),
  247. jsonrpc:'2.0',
  248. method:'aria2.addUri',
  249. params:[
  250. [res.web_content_link],
  251. { out: res.name }
  252. ]
  253. }
  254. ariaPath && (ariaData.params[1].dir = ariaPath)
  255. ariaToken && (ariaData.params.unshift(`token:${ariaToken}`))
  256. let ariares = {}
  257. if (['Android','IOS'].includes(getPlatform()) && !GM_xmlhttpRequest) {
  258. ariares = await postData(ariaHost, ariaData,{}, 'POST')
  259. } else {
  260. ariares = await post(ariaHost, ariaData, {}, '')
  261. }
  262. console.log('ariares', ariares)
  263. if(ariares.result) {
  264. Toast(toast, 'aria2下载成功')
  265. } else {
  266. Toast(toast, 'aria2下载失败,请查看配置')
  267. }
  268. } catch(e) {
  269. console.log('ariares', e)
  270. }
  271. })
  272. }
  273. }, 1000)
  274. // Your code here...
  275. })();