diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index acb3eb238ac..0508af3ebb1 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,3 +1,3 @@ # These are supported funding model platforms ko_fi: hoothin -custom: ["https://paypal.me/hoothin", "https://afdian.net/a/hoothin"] +custom: ["https://paypal.me/hoothin", "https://afdian.com/a/hoothin"] diff --git a/.github/ISSUE_TEMPLATE/custom-rule-request.md b/.github/ISSUE_TEMPLATE/custom-rule-request.md index f5e42694275..d012e0245f3 100644 --- a/.github/ISSUE_TEMPLATE/custom-rule-request.md +++ b/.github/ISSUE_TEMPLATE/custom-rule-request.md @@ -1,7 +1,7 @@ --- name: Custom rule request about: Seek help for custom rule. Please publish the issue according to the guidelines, - otherwise the request will be ignored and closed directly. Your understanding and + otherwise the request ⚠will be ignored and closed directly⚠. Your understanding and cooperation are appreciated. title: '' labels: '' @@ -10,7 +10,7 @@ assignees: '' --- **The url of site** -The example urls of site. Do not paste only domain without pathname. +The example urls of site. ⚠**Do not paste only domain without pathname, or I'll close the issue without explanation**⚠. **Is your request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] diff --git a/.github/workflows/build-dist.yml b/.github/workflows/build-dist.yml new file mode 100644 index 00000000000..ef4f9880fb6 --- /dev/null +++ b/.github/workflows/build-dist.yml @@ -0,0 +1,33 @@ +name: Build Picviewer CE+ Dist + +on: + push: + branches: + - master + paths: + - 'Picviewer CE*/Picviewer CE*.user.js' + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Replace require paths, add timestamp, and create dist file + run: | + sed -E \ + -e "s#https://update.greasyfork.org/scripts/6158/([0-9]+)/GM_config%20CN.js#https://hoothin.github.io/UserScripts/Picviewer%20CE%2B/GM_config%20CN.js?v=\1#g" \ + -e "s#https://update.greasyfork.org/scripts/438080/([0-9]+)/pvcep_rules.js#https://hoothin.github.io/UserScripts/Picviewer%20CE%2B/pvcep_rules.js?v=\1#g" \ + -e "s#https://update.greasyfork.org/scripts/440698/([0-9]+)/pvcep_lang.js#https://hoothin.github.io/UserScripts/Picviewer%20CE%2B/pvcep_lang.js?v=\1#g" \ + "Picviewer CE+/Picviewer CE+.user.js" > "Picviewer CE+/dist.user.js" + + - name: Commit and push dist.user.js + run: | + git config --local user.email "rixixi@gmail.com" + git config --local user.name "hoothin-update" + git add "Picviewer CE+/dist.user.js" + git commit -m "chore(Picviewer CE+): Auto-generate dist.user.js" + git push https://${{ secrets.ACTION_SECRET }}@github.com/${{ github.repository }} diff --git a/.github/workflows/jekyll-gh-pages.yml b/.github/workflows/jekyll-gh-pages.yml new file mode 100644 index 00000000000..9bdd4e3eec5 --- /dev/null +++ b/.github/workflows/jekyll-gh-pages.yml @@ -0,0 +1,60 @@ +# Sample workflow for building and deploying a Jekyll site to GitHub Pages +name: Deploy Jekyll with GitHub Pages dependencies preinstalled + +on: + # Runs on pushes targeting the default branch + push: + branches: ["master"] + paths-ignore: + - 'Pagetual/items_all.json' + - 'Pagetual/pagetualRules.json' + - '.github/*' + - '.github/*/*' + workflow_run: + workflows: ["Update Version on File Change"] + types: + - completed + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Build with Jekyll + uses: actions/jekyll-build-pages@v1 + with: + source: ./ + destination: ./_site + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/json-validator.yml b/.github/workflows/json-validator.yml new file mode 100644 index 00000000000..01911cc1730 --- /dev/null +++ b/.github/workflows/json-validator.yml @@ -0,0 +1,21 @@ +name: Validate JSON + +on: + pull_request: + paths: + - 'Pagetual/pagetualRules.json' + +jobs: + validate-json: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: json-yaml-validate + uses: GrantBirki/json-yaml-validate@v5 + id: json-yaml-validate + with: + json_schema: Pagetual/pagetual.schema.json + files: | + Pagetual/pagetualRules.json diff --git a/.github/workflows/update_version.yml b/.github/workflows/update_version.yml new file mode 100644 index 00000000000..0d1af146533 --- /dev/null +++ b/.github/workflows/update_version.yml @@ -0,0 +1,51 @@ +name: Update Version on File Change +on: + push: + paths: + - 'Pagetual/items_all.json' + - 'Pagetual/pagetualRules.json' + workflow_run: + workflows: ["Collect wedata for pagetual"] + types: + - completed + +jobs: + update_version: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check file modification timestamps + id: check_file_timestamps + run: | + version_timestamp=$(git log -1 --format="%at" Pagetual/version) + items_all_timestamp=$(git log -1 --format="%at" Pagetual/items_all.json) + pagetualRules_timestamp=$(git log -1 --format="%at" Pagetual/pagetualRules.json) + if [[ $version_timestamp < $items_all_timestamp || $version_timestamp < $pagetualRules_timestamp ]]; then + version=$(cat Pagetual/version) + else + version=0 + echo "Version file is not updated. Skipping version read." + fi + echo "VERSION=$version" >> $GITHUB_ENV + + - name: Increment version + if: env.VERSION != '0' + id: increment_version + run: echo "VERSION=$((VERSION + 1))" >> $GITHUB_ENV + + - name: Update version file + if: env.VERSION != '0' + run: echo $VERSION > Pagetual/version + + - name: Commit version update + if: env.VERSION != '0' + run: | + git config --local user.email "rixixi@gmail.com" + git config --local user.name "hoothin-update" + git add Pagetual/version + git commit -m "Update version of Pagetual rules to $VERSION" + git push https://${{ secrets.ACTION_SECRET }}@github.com/${{ github.repository }} diff --git a/91wii/91wii.user.js b/91wii/91wii.user.js deleted file mode 100644 index b94c7d4fd79..00000000000 --- a/91wii/91wii.user.js +++ /dev/null @@ -1,50 +0,0 @@ -// ==UserScript== -// @name 91wii -// @namespace hoothin -// @version 0.6 -// @description 91wii签到 -// @author hoothin -// @match https://*.91wii.com/* -// @match https://*.91tvg.com/* -// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== -// @run-at document-idle -// @grant unsafeWindow -// ==/UserScript== - -(function() { - 'use strict'; - setTimeout(()=>{ - var formula = document.querySelector("b"),dcsignin = document.querySelector("#dcsignin_tips"); - if(formula && /^[\d\s\+-=?]+$/.test(formula.innerText.trim())){ - setTimeout(function(){ - document.querySelector("input[type=text]").value=eval(formula.innerText.match(/[\d\s\+-]+/)[0]); - document.querySelector("input[type=submit]").click(); - },10); - }else if(dcsignin){ - if(dcsignin.style.background.indexOf("signin_yes") != -1)return; - unsafeWindow.showWindow('sign', 'plugin.php?id=dc_signin:sign'); - var checkTimes=0; - let signInterval=setInterval(()=>{ - var signWin=document.querySelector("#fwin_sign"); - if(signWin){ - signWin.style.display="none"; - } - var dialogWin=document.querySelector("#fwin_dialog"); - if(dialogWin){ - dialogWin.style.display="none"; - } - let emotIndex=parseInt(Math.random() * 10) + 1; - if(document.querySelector("#emot_" + emotIndex)){ - clearInterval(signInterval); - document.querySelector("#emot_" + emotIndex).click(); - //document.querySelector('#content').value = '君子有四时,朝以听政,昼以访问,夕以修令,夜以安身。'; - document.querySelector("button[name=signpn]").click(); - unsafeWindow.hideWindow('sign'); - }else if(checkTimes++>15){ - clearInterval(signInterval); - unsafeWindow.hideWindow('sign'); - } - }, 100); - } - },2000); -})(); \ No newline at end of file diff --git a/91wii/README.md b/91wii/README.md deleted file mode 100644 index d7cb01b5315..00000000000 --- a/91wii/README.md +++ /dev/null @@ -1 +0,0 @@ -# 91wii 自动作答数学题,自动签到 diff --git a/Appinn Comment/AppinnComment.user.js b/Appinn Comment/AppinnComment.user.js new file mode 100644 index 00000000000..46076e191bc --- /dev/null +++ b/Appinn Comment/AppinnComment.user.js @@ -0,0 +1,46 @@ +// ==UserScript== +// @name Appinn comment +// @name:zh-CN 小众软件评论显示 +// @namespace hoothin +// @version 2024-06-08 +// @description Display the comments from the Appinn forum on the bottom of the corresponding page on the main site. +// @description:zh-CN 将小众软件论坛的评论内容显示在主站对应页面下部 +// @author hoothin +// @match https://www.appinn.com/* +// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== +// @grant GM_xmlhttpRequest +// @connect meta.appinn.net +// @downloadURL https://update.greasyfork.org/scripts/497293/Appinn%20comment.user.js +// @updateURL https://update.greasyfork.org/scripts/497293/Appinn%20comment.meta.js +// ==/UserScript== + +(function() { + 'use strict'; + const commentLink = document.querySelector('a.wpdc-join-discussion-link'); + if (!commentLink) return; + GM_xmlhttpRequest({ + url: commentLink.href, + method: 'GET', + onload: function(res) { + try { + let doc = document.implementation.createHTMLDocument(''); + doc.documentElement.innerHTML = res.response; + let dataPreloaded = doc.getElementById('data-preloaded'); + if (!dataPreloaded) return; + dataPreloaded = JSON.parse(JSON.parse(dataPreloaded.dataset.preloaded)["topic_" + commentLink.href.match(/\d+/)[0]]).post_stream.posts; + let posts = document.createElement("ul"); + posts.style.maxHeight = '90vh'; + posts.style.overflow = 'auto'; + posts.style.margin = '0'; + let title = document.createElement("h3"); + title.innerText = "评论内容"; + document.querySelector('article').appendChild(title); + document.querySelector('article').appendChild(posts); + dataPreloaded.forEach(item => { + posts.innerHTML += `
${item.display_username || item.username}
${item.cooked}
某個章節名 / CSS 選擇器【選擇器後可跟 >> 傳入 item 處理】 **@@** 抓取到 URL 的正則匹配 **@@** 正則替換 URL **@@** 根據爬取返回內容 data 處理並返回最終文本
+某個章節名 / CSS 選擇器【選擇器後可跟 >> 傳入 item 處理】 **@@** 抓取到 URL 的正規表示式匹配 **@@** 正規表示式替換 URL **@@** 根據爬取返回內容 data 進行處理並回傳最終文本
+#### 内頁處理範例
+假設章節元素為 `a.links`
++ 使用 iframe 處理内頁内容
+ `a.links@@@@@@iframe:`
+ - iframe 添加 sandbox
+ `a.links@@@@@@iframe:sandbox:{allow-same-origin}`
+ - iframe 添加初始化程式碼
+ `a.links@@@@@@iframe:init:{win.top=win.self}`
++ 自訂内頁中分頁抓取方式
+ - 透過選擇器抓取
+ `a.links@@@@@@next:{a.next}`
+ - 透過程式碼生成
+ `a.links@@@@@@next:{return await getNextElement()}` 可以用多層 `{}` 來避免程式碼中出現大括號產生的問題
-### 自定義下載範例,打開目錄頁點擊【自定義下載】粘貼後使用
- 1. [📕po18](https://www.po18.tw/books/755779/articles),章節的選擇器為 `.l_chaptname>a` ,輸入並下載後發現通過 url 無法下載正文內容,正文是 ajax 通過 articlescontent 下載的。此時可後接 `@@articles@@articlescontent` (@@ 分隔) 將章節 url 中的 articles 替換為 articlescontent 。 `.l_chaptname>a@@articles@@articlescontent` 粘貼進命令菜單即可下載。其中第一個 articles 可使用正則,例如 `@@articles(\d+)@@$1content` 代表將連結中的「articles1」「articles2」等替換為「1content」「2content」。
+### 自訂下載範例,打開目錄頁點擊【自訂下載】粘貼後使用,僅爲規則實例引導,有出入請自行修改
++ [📕po18](https://www.po18.tw/books/755779/articles)
+> 章節的選擇器為 `.l_chaptname>a` ,輸入並下載後發現通過 url 無法下載正文內容,正文是 ajax 通過 articlescontent 下載的。此時可後接 `@@articles@@articlescontent` (@@ 分隔) 將章節 url 中的 articles 替換為 articlescontent 。 `.l_chaptname>a@@articles@@articlescontent` 粘貼進命令菜單即可下載。其中第一個 articles 可使用正規表示式,例如 `@@articles(\d+)@@$1content` 代表將連結中的「articles1」「articles2」等替換為「1content」「2content」。
``` css
-.l_chaptname>a @@ articles @@ articlescontent
+.l_chaptname>a@@articles@@articlescontent
```
- 如果需要下載已購買的vip章節,用這個規則
+ > 如果需要下載已購買的vip章節,用這個規則
``` javascript
a.btn_L_blue>>let a=document.createElement("a");a.innerText=item.parentNode.parentNode.querySelector('.l_chaptname').innerText;a.href=item.href;return a;@@articles@@articlescontent
```
- 2. [📕pixiv](https://www.pixiv.net/novel/series/7807554),p站小說的章節選擇器為`main>section ul>li>div>a`,無需替換連結,因此後兩項留空。有6個@了 😂。正文在meta裡,需要自定義代碼提取meta-preload數據的content項。其中 "doc" 代表抓取網頁的document對象,若返回的是純文本,則用 `doc.body.innerText` 獲取。
++ [📕pixiv](https://www.pixiv.net/novel/series/7807554)
+> p站小說的章節選擇器為`main>section ul>li div>a`,無需替換連結,因此後兩項留空。有6個@了 😂。正文在meta裡,需要自定義代碼提取meta-preload數據的content項。其中 "doc" 代表抓取網頁的document對象,若返回的是純文本,則用 `doc.body.innerText` 獲取。
+ ``` javascript
+main>section ul>li div>a@@@@@@var noval=JSON.parse(doc.querySelector("#meta-preload-data").content).novel;noval[Object.keys(noval)[0]].content;
+ ```
+ 新規則
``` javascript
-main>section ul>li>div>a @@@@@@ var noval=JSON.parse(doc.querySelector("#meta-preload-data").content).novel;noval[Object.keys(noval)[0]].content;
+main>section ul>li div>a@@novel/show\.php\?id=@@ajax/novel/@@data.json().body.content;
```
- 3. [📕紅薯中文網](https://g.hongshu.com/chapterlist/91735.do),這個站沒有目錄連結,此時可以遍歷標籤自己創建目錄連結下載
++ [📕紅薯中文網](https://g.hongshu.com/chapterlist/91735.do)
+> 這個站沒有目錄連結,此時可以遍歷標籤自己創建目錄連結下載
``` javascript
ul#lists>li>>let href=item.getAttribute("onclick").replace(/.*(http.*html).*/,"$1"),innerText=item.querySelector("span").innerText;return {href:href,innerText:innerText};@@@@@@let rdtext=data.querySelector('div.rdtext');let sc=data.querySelector('div.ewm+script');if(sc&&rdtext){let code=sc.innerText.replace(/for\(var i=0x0;i/g,"").replace(/<\/p>/g,"\n"));};document.head.appendChild(cryptojs);return false; ``` - 18. [📕豆瓣閲讀](https://read.douban.com/column/64079189/) ++ [📕某瓣](https://read.某瓣.com/column/64079189/) ``` css a.chapter-item ``` - > 礙於法律問題,不會給出具體規則。只因爲有朋友詢問,所以手癢分析了一下,給出相關思路以供技術研究。後期如若豆瓣更新則不再跟進。首先,豆瓣閲讀的内頁只有部分内容是明文,全文被加密了。每次訪問内頁,豆瓣會先檢索本地存儲中是否存在密文,如果不存在的話就去抓取密文,密文為 digest 的 sha256 加密得到,解密方法如下: - ``` javascript +> 礙於法律問題,不會給出具體規則。只因爲有朋友詢問,所以手癢分析了一下,給出相關思路以供技術研究,請勿來問我要現成規則。後期如若有變動不再跟進。具體操作請自行摸索,後果自負。 +> 首先,某瓣的内頁只有部分内容是明文,全文被加密了。每次訪問内頁,它會先檢索本地存儲中是否存在密文,如果不存在的話就去抓取密文,密文為 digest 的 sha256 加密得到。 +> 因此步驟如下,首先調用 article_v2/get_reader_data, 透過表單形式提供當前章節的 aid(即爲 chapter 后的數字串),獲取 json.data 即爲密文,然後透過上方的解密方法獲取正文。正文位於 posts[0].contents 中,遍歷后讀取 data.text[0].content 拼接。 +> 解密方法如下: +``` javascript function decode(t) { const s = (new TextDecoder).decode(new Uint8Array([65, 69, 83, 45, 67, 66, 67])) , r = (new TextDecoder).decode(new Uint8Array([99, 114, 121, 112, 116, 111])) @@ -170,14 +211,29 @@ function decode(t) { return window[r][o][a](h, i).then((t=>window[r][o][l]("raw", t, s, !0, [c]))) }().then((t=>window[r][o][c](g, t, f))).then((t=>JSON.parse((new TextDecoder).decode(t)))) } - ``` - > 因此規則可按如下步驟編寫,首先調用 https://read.douban.com/j/article_v2/get_reader_data, 透過表單形式提供當前章節的 aid(即爲 chapter 后的數字串),獲取 json.data 即爲密文,然後透過上方的解密方法獲取正文。正文位於 posts[0].contents 中,遍歷后讀取 data.text[0].content 拼接即可 - 19. [📕愛發電](https://afdian.net/album/afee5ce2462d11ee897e52540025c377) - > 礙於我也是愛發電用戶,拿人手短,就不欺負它了。只給個思路,用第四層心法取 album_id 與 章節 id 去 https://afdian.net/api/post 請求數據即可。 +``` + ++ [📕愛發電](https://愛發電/album/afee5ce2462d11ee897e52540025c377) +> 我也是愛發電用戶,拿人手短,就不欺負它了。只給個思路,用第四層心法取 album_id 與 章節 id 去 /api/post 請求數據即可。 ++ [📕頭文字小説](https://m.touwz.net/dushi/yinhezhuiluo/) +> 簡單的分頁,沒啥難點。惟一需要注意的是,分頁連結藏在 js 代碼裏,用正規表示式取出完事。 +``` javascript +.chapter>li>a@@@@@@let content="\n";let checkContent=(doc,over)=>{word=doc.querySelector('.content-div');if(!word)content+='\n'+doc.body.innerText;else {let ps=[];[].forEach.call(word.children, p=>{if(p.className!='moreinfo')ps.push(p.innerText)});content+=ps.join('\n');}let next=doc.querySelector("#pt_next");if(next){fetch(location.href+ doc.body.innerHTML.match(/'([^\|']+)\|[^']+'\.split/)[1]+".html").then(r => r.text()).then(d => {let _doc = document.implementation.createHTMLDocument('');_doc.documentElement.innerHTML = d;checkContent(_doc,over);});}else over();};checkContent(data,()=>{cb(content.replace(/\s*「如章节缺失请退#出#阅#读#模#式」\s*|\s*本章未完,点下一页继续阅读。>>>\s*/g,''))});return false; +``` ++ [📕H圖書館](https://hlib.cc/s/sis-9732262) +> 簡單的分頁,可以使用簡化規則,傳入内分頁的選擇器,其餘交給脚本自動處理。 +``` javascript +.list-group-item>div>a.text-decoration-none@@@@@@next:{[aria-label='后一页']+a} +``` ++ [📕又一個頂點小説網](https://www.booktxts.com/book/77/77540/2.html) +> 首先遍歷目錄,生成實際鏈接,再分析頁内代碼,調用網站自身的解密函數解密内容,最後分析下一頁鏈接,把分頁内容補上。 +``` javascript +.yanqing_list>li>a>>item.href=item.getAttribute('onclick').replace(/.*\((.*)\)/, location.href.replace(/\d+\.html/,'').replace('/book/','/books/')+'$1.html');return item;@@@@@@let content='';let anylize=doc=>{let contentTags=doc.body.innerHTML.match(/",'')).replace(/<.?p>/g,'')+'\n'}); let nextLink=doc.querySelector('.read_btn>a:last-child'); if(/\_\d+\.html/.test(nextLink.href)){ let fetchNext=()=>{return fetch(nextLink.href).then(res => res.text()).then(d=>{let _doc = document.implementation.createHTMLDocument(''); _doc.documentElement.innerHTML = d;anylize(_doc);})}; fetchNext().catch(e=>{fetchNext()}); }else{cb(content);} };let script=document.createElement('script');script.src='https://www.booktxts.com/yanqing/pc/js/yueduqsbs.js';script.type = "text/javascript";document.body.appendChild(script);script.onload=e=>{anylize(doc);};return false; +``` ### 測試網頁 + http://www.gulongbbs.com/zhentan/bdlr/plje/Index.html -+ http://www.jhshe.cn/thread-1837-1-1.html ++ http://www.jhshe.com/thread-1837-1-1.html + http://tieba.baidu.com/p/4871634479 ### FAQ diff --git a/Easy offline/Easy offline pikpak.user.js b/Easy offline/Easy offline pikpak.user.js new file mode 100644 index 00000000000..8550d395dc0 --- /dev/null +++ b/Easy offline/Easy offline pikpak.user.js @@ -0,0 +1,249 @@ +// ==UserScript== +// @name Easy Offline pikpak addon +// @namespace hoothin +// @version 2024-08-16 +// @description Add pikpak support for Easy Offline +// @author hoothin +// @match *://*/* +// @grant GM_setValue +// @grant GM_getValue +// @grant GM_xmlhttpRequest +// @grant GM_notification +// @grant unsafeWindow +// @run-at document-start +// @require https://unpkg.com/crypto-js@4.2.0/crypto-js.js +// @connect user.mypikpak.com +// @connect api-drive.mypikpak.com +// ==/UserScript== + +(function() { + 'use strict'; + let info = GM_getValue("pikpakUserInfo"), device_id, user_id; + const CLIENT_ID = "YNxT9w7GMdWvEOKa"; + const CLIENT_SECRET = "dbw2OtmVEeuUvIptb1Coyg"; + const CLIENT_VERSION = "1.47.1"; + const PACKAG_ENAME = "com.pikcloud.pikpak"; + const SDK_VERSION = "2.0.4.204000"; + const APP_NAME = "com.pikcloud.pikpak"; + function captchaInit() { + return new Promise(resolve => { + let meta = {}; + if (/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(info.userName)) { + meta.email = info.userName; + } else if (/\d{11,18}/.test(info.userName)) { + meta.phone_number = info.userName; + } else { + meta.username = info.userName; + } + let params = { + "client_id": CLIENT_ID, + "action": "POST:https://user.mypikpak.com/v1/auth/signin", + "device_id": device_id, + "meta": meta + } + GM_xmlhttpRequest({ + method: 'POST', + url: 'https://user.mypikpak.com/v1/shield/captcha/init', + data: JSON.stringify(params), + onload: (res) => { + if(res.status === 200) { + let data = JSON.parse(res.responseText); + resolve(data); + } else { + info.loginInfo = null; + GM_setValue("pikpakUserInfo", info); + const msg = JSON.parse(res.responseText).error_description; + alert(msg); + } + }, + onerror: (e) => { + GM_notification("Error: " + (e.statusText || e.error)); + }, + ontimeout: (e) => { + GM_notification("Error: " + (e.statusText || e.error)); + } + }); + }); + } + function buildCustomUserAgent() { + let signature_base = `${device_id}${PACKAG_ENAME}1appkey`; + let sha1_result = CryptoJS.SHA1(signature_base).toString(CryptoJS.enc.Hex); + let md5_result = CryptoJS.MD5(sha1_result).toString(CryptoJS.enc.Hex); + + let device_sign = `div101.${device_id}${md5_result}`; + + let user_agent_parts = [ + `ANDROID-${APP_NAME}/${CLIENT_VERSION}`, + "protocolVersion/200", + "accesstype/", + `clientid/${CLIENT_ID}`, + `clientversion/${CLIENT_VERSION}`, + "action_type/", + "networktype/WIFI", + "sessionid/", + `deviceid/${device_id}`, + "providername/NONE", + `devicesign/${device_sign}`, + "refresh_token/", + `sdkversion/${SDK_VERSION}`, + `datetime/${Date.now()}`, + `usrno/${user_id}`, + `appname/${APP_NAME}`, + "session_origin/", + "grant_type/", + "appid/", + "clientip/", + "devicename/Xiaomi_M2004j7ac", + "osversion/13", + "platformversion/10", + "accessmode/", + "devicemodel/M2004J7AC", + ] + + return user_agent_parts.join(" "); + } + document.addEventListener("click", function(e) { + if (e.target && e.target.getAttribute && e.target.getAttribute("name") === "pikpak" && e.target.parentNode.id === "icons") { + GM_setValue("pikpakUserInfo", ""); + alert("PikPak account has been cleared"); + } + }); + var _unsafeWindow = (typeof unsafeWindow === 'undefined') ? window : unsafeWindow; + if (!_unsafeWindow.eoAddons) _unsafeWindow.eoAddons = {}; + _unsafeWindow.eoAddons.pikpak = { + regex: /mypikpak\.com/, + url: "http://user.mypikpak.com/", + bgColor: "2265ff", + noTxt: true, + linkRegExp: /^magnet:\?xt|^PikPak:\/\/|\.(torrent|mp4|mp3|rar|7z|zip|rmvb|mkv|avi|iso)$/i, + directUrl: function(offUrl) { + if (!info) { + let userName = prompt("userName"); + if (!userName) return; + let userPass = prompt("userPass"); + if (!userPass) return; + info = {userName: userName, userPass: userPass}; + GM_setValue("pikpakUserInfo", info); + } + var postUrl = async () => { + let postData; + if (offUrl.indexOf('PikPak://') === 0) { + const urlData = offUrl.substring(9).split('|') + postData = { + kind: "drive#file", + name: urlData[0], + size: urlData[1], + hash: urlData[2], + upload_type: "UPLOAD_TYPE_RESUMABLE", + objProvider: { + provider: "UPLOAD_TYPE_UNKNOWN" + } + } + } else { + postData = { + kind: "drive#file", + name: "", + upload_type: "UPLOAD_TYPE_URL", + url: { + url: offUrl + }, + params: {"from":"file"}, + folder_type: "DOWNLOAD" + } + } + GM_xmlhttpRequest({ + method: 'POST', + url: 'https://api-drive.mypikpak.com/drive/v1/files', + data: JSON.stringify(postData), + headers: { + "Content-Type": "application/json; charset=utf-8", + authorization: info.loginInfo.token_type + ' ' + info.loginInfo.access_token, + "X-Captcha-Token": info.captchaData.captcha_token + }, + onload: (res) => { + if(res.status === 200) { + GM_notification("Task OK"); + } else if(res.status === 401) { + info.loginInfo=null; + GM_setValue("pikpakUserInfo", info); + const msg = JSON.parse(res.responseText).error_description; + alert(msg); + } else if(res.status === 400) { + const msg = JSON.parse(res.responseText).error_description; + alert(msg); + } else if(res.status === 403) { + const msg = JSON.parse(res.responseText).error_description; + alert(msg); + } + }, + onerror: (e) => { + GM_notification("Error: " + (e.statusText || e.error)); + }, + ontimeout: (e) => { + GM_notification("Error: " + (e.statusText || e.error)); + } + }) + }; + device_id = CryptoJS.MD5(`${info.userName}${info.userPass}`).toString(CryptoJS.enc.Hex); + (async () => { + if (!info.captchaData || info.captchaData.expires < new Date().getTime()) { + let captchaData = await captchaInit(); + info.captchaData = captchaData; + if (!info.captchaData.expires && info.captchaData.expires_in) { + info.captchaData.expires = new Date().getTime() + 1000 * info.captchaData.expires_in; + } + GM_setValue("pikpakUserInfo", info); + } + if (!info.loginInfo || info.loginInfo.expires < new Date().getTime()) { + let data = { + "client_id": CLIENT_ID, + "client_secret": CLIENT_SECRET, + "password": info.userPass, + "username": info.userName, + "captcha_token": info.captchaData.captcha_token, + } + GM_xmlhttpRequest({ + method: 'POST', + url: 'https://user.mypikpak.com/v1/auth/signin', + data: JSON.stringify(data), + headers: { + 'user-agent': 'accessmode/ devicename/Netease_Mumu appname/android-com.pikcloud.pikpak cmd/login appid/ action_type/ clientid/YNxT9w7GMdWvEOKa deviceid/56e000d71f4660700ca974f2305171c5 refresh_token/ grant_type/ networktype/WIFI devicemodel/MuMu accesstype/ sessionid/ osversion/6.0.1 datetime/1636364470779 sdkversion/1.0.1.101600 protocolversion/200 clientversion/ providername/NONE clientip/ session_origin/ devicesign/div101.56e000d71f4660700ca974f2305171c5b94c3d4196a9dd74e49d7710a7af873d platformversion/10 usrno/null' + }, + onload: (res) => { + if (res.status === 200) { + info.loginInfo = JSON.parse(res.responseText); + if (!info.loginInfo.expires && info.loginInfo.expires_in) { + info.loginInfo.expires = new Date().getTime() + 1000 * info.loginInfo.expires_in; + } + GM_setValue("pikpakUserInfo", info); + postUrl(); + } else if (res.status === 401) { + GM_setValue("pikpakUserInfo",""); + const msg = JSON.parse(res.responseText).error_description; + alert(msg); + } else if (res.status === 400) { + GM_setValue("pikpakUserInfo",""); + const msg = JSON.parse(res.responseText).error_description; + alert(msg); + } else if (res.status === 403) { + GM_setValue("pikpakUserInfo",""); + const msg = JSON.parse(res.responseText).error_description; + alert(msg); + } + }, + onerror: (e) => { + GM_notification("Error: " + (e.statusText || e.error)); + }, + ontimeout: (e) => { + GM_notification("Error: " + (e.statusText || e.error)); + } + }) + } else { + postUrl(); + } + })(); + return false; + }, + bgImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAYFBMVEUAAAArbP5MdNFMdNIrbP4sbP1QdctQdcwvbv////8dYf8sbP9smP/09/8qaf/V4f8iZf/u8/+lwP+duv+UtP+PsP9hkP92n/9nlP/K2v/F1v+7z/+Ytv9Wif9Aef91nv9e7pgKAAAACHRSTlMA+puT/PWHhQBB7XEAAACQSURBVBjTTY8JCsQwCEWdrjFm37p37n/LMdAJfSTgf4IoAPQf8fDpgek4N9NxnwQZJx0/w+UMNd/XV6nluqsBQbRp79Xqvd7ICBCuaHuElMJhdXEspMKGko/YA2LYXyKuiGt8Ca3rfwm052nbjILV1IyFBZFZck4xppwXQ8Srk2wQzXzcIBpDB8w0/vM4AfwACl4LKjajMX0AAAAASUVORK5CYII=" + }; +})(); \ No newline at end of file diff --git a/Easy offline/Easy offline.user.js b/Easy offline/Easy offline.user.js index b5e0758409e..a95eadbffb3 100644 --- a/Easy offline/Easy offline.user.js +++ b/Easy offline/Easy offline.user.js @@ -7,7 +7,7 @@ // @description:zh-TW 一鍵離綫下載 - 一鍵自動將磁鏈、bt種子或其他下載資源離綫下載至網盤 // @namespace https://github.com/hoothin/UserScripts/tree/master/Easy%20offline // @require http://code.jquery.com/jquery-1.7.2.min.js -// @version 1.9.39.2 +// @version 1.9.41 // @author Hoothin // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAQlBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////8IX9KGAAAAFXRSTlMAwT7hFahN0LZWJgqIavB7YJuRdDPJsaCPAAAA6ElEQVQ4y8WRW5aEIAxEDUGgAQUftf+tjgYOjcPMb3d96Im5pkIxfVgmOuY5mX/afkYVqb/6EXDGh+CNA7axvwOvZrUiDfalX6UY5y+AkZ687Ut9WNgw9SLYQ3cDYfNz4kIAq2Z/wYN0AiSRQN16iroMXnD3K2F+f1oBLK2ckeWpmjFEsc2Tfxn6ndUBLGgjNVgAX8oNa56AO8dKeAEccnW89ruB6bQVWGTL2IcmQJOTdXSdOAIRrMtxsekR8AQ5XyHARLTrAhi6xH0iYWfcOguQpeAtPJJXSvlqEdSl4XaGHb4HEE0f1w+Jcw2XCZjSwgAAAABJRU5ErkJggg== // @match *://*/* @@ -386,119 +386,6 @@ }, bgImg:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAA9lBMVEUAAACgoqOipKUAAAC4ubq1traXl5jX19g9PT4GBga2t7ixsrOur7Cmp6jMzM1+f39ZWVpnZ2eChIXMzc3BwcKvsrLGxsacnZ3f399zdHS9vr61trZZW1upq6vIysq7vb2nqKliZGTS09O6vLzg4OC2uLhQUVHi4uK+v79OTk4hISHT1NQZGRnf4OCPkpKsra3KysxmZ2d+f3/y8vOUlZW+vr+2tridnp/Z2dmAgYJ4enptbm5YWVn39/fv7/DDw8Td3d7U1dXU1NTOztC4ubuoqamlpaWcnJyYmJp6fHxwcXFTVVX29/bHyMnHx8e3t7qgoaGHiYm1AxJpAAAAL3RSTlMAHhgF4NbW2jQU4uDg3sybVDUkHhcF6Ojk5ODc2dfJycPDra17ezkuLiUlIRUREf6sWL0AAAC0SURBVBjTjY9HEoJAAAQXVwVzAMw5Z5YMgoBizv7/M7JwoLw5t+lD1wzAYVcEPaeXLAgyHvTazTpJtvrDCe5M1nUReiiK/ERZxgNEVLYdy1GFz1uuET54IfGucTq/5qIYRGIKEjcaJ3ggFsEgrp/tnSwZJi/EMSDSqqQeJeNmXk+pwLFHlrg9CPzl16H/7ygmQ0eyCACkMuGODAUBTORzHbJSKlcb3Vw+AfE9uJgWCiNq5rcvfNwgjdumYdQAAAAASUVORK5CYII=" }, - PikPak:{ - regex:/mypikpak\.com/, - url:"http://user.mypikpak.com/", - bgColor:"2265ff", - noTxt:true, - linkRegExp: /^magnet:\?xt|^PikPak:\/\/|\.(torrent|mp4|mp3|rar|7z|zip|rmvb|mkv|avi|iso)$/i, - directUrl:function(offUrl){ - //此段代码引用自 mumuchenchen 大佬的 PikPak 保存助手 https://greasyfork.org/scripts/435219 - //mumuchenchen 的第三方 Pikpak 网页客户端 推荐大家前往 fork https://github.com/mumuchenchen/pikpak - storage.getItem("pikpakUserInfo",info=>{ - if(!info){ - let userName=prompt(i18n("userName")); - if(!userName)return; - let userPass=prompt(i18n("userPass")); - if(!userPass)return; - info={userName:userName,userPass:userPass}; - storage.setItem("pikpakUserInfo",info); - } - var postUrl=()=>{ - let postData; - if(offUrl.indexOf('PikPak://') === 0) { - const urlData = offUrl.substring(9).split('|') - postData = { - kind: "drive#file", - name: urlData[0], - size: urlData[1], - hash: urlData[2], - upload_type: "UPLOAD_TYPE_RESUMABLE", - objProvider: { - provider: "UPLOAD_TYPE_UNKNOWN" - } - } - } else { - postData = { - kind: "drive#file", - name: "", - upload_type: "UPLOAD_TYPE_URL", - url: { - url: offUrl - }, - params: {"from":"file"}, - folder_type: "DOWNLOAD" - } - } - _GM_xmlhttpRequest({ - method: 'POST', - url: 'https://api-drive.mypikpak.com/drive/v1/files', - data: JSON.stringify(postData), - headers: { - authorization: info.loginInfo.token_type + ' ' + info.loginInfo.access_token - }, - onload: (res) => { - if(res.status === 200) { - _GM_notification("Task OK"); - } else if(res.status === 401) { - info.loginInfo=null; - storage.setItem("pikpakUserInfo",info); - const msg = JSON.parse(res.responseText).error_description; - alert(msg); - } else if(res.status === 400) { - const msg = JSON.parse(res.responseText).error_description; - alert(msg); - } else if(res.status === 403) { - const msg = JSON.parse(res.responseText).error_description; - alert(msg); - } - } - }) - }; - if(!info.loginInfo || info.loginInfo.expires < new Date().getTime()){ - _GM_xmlhttpRequest({ - method: 'POST', - url: 'https://user.mypikpak.com/v1/auth/signin', - data: JSON.stringify({ - "client_id": "YNxT9w7GMdWvEOKa", - "client_secret": "dbw2OtmVEeuUvIptb1Coyg", - "password": info.userPass, - "username": info.userName - }), - headers: { - 'user-agent': 'accessmode/ devicename/Netease_Mumu appname/android-com.pikcloud.pikpak cmd/login appid/ action_type/ clientid/YNxT9w7GMdWvEOKa deviceid/56e000d71f4660700ca974f2305171c5 refresh_token/ grant_type/ networktype/WIFI devicemodel/MuMu accesstype/ sessionid/ osversion/6.0.1 datetime/1636364470779 sdkversion/1.0.1.101600 protocolversion/200 clientversion/ providername/NONE clientip/ session_origin/ devicesign/div101.56e000d71f4660700ca974f2305171c5b94c3d4196a9dd74e49d7710a7af873d platformversion/10 usrno/null' - }, - onload: (res) => { - if(res.status === 200) { - info.loginInfo=JSON.parse(res.responseText); - if(!info.loginInfo.expires && info.loginInfo.expires_in){ - info.loginInfo.expires = new Date().getTime() + 1000 * info.loginInfo.expires_in; - } - storage.setItem("pikpakUserInfo",info); - postUrl(); - } else if(res.status === 401) { - storage.setItem("pikpakUserInfo",""); - const msg = JSON.parse(res.responseText).error_description; - alert(msg); - } else if(res.status === 400) { - storage.setItem("pikpakUserInfo",""); - const msg = JSON.parse(res.responseText).error_description; - alert(msg); - } else if(res.status === 403) { - storage.setItem("pikpakUserInfo",""); - const msg = JSON.parse(res.responseText).error_description; - alert(msg); - } - } - }) - }else{ - postUrl(); - } - }); - return false; - }, - bgImg:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAYFBMVEUAAAArbP5MdNFMdNIrbP4sbP1QdctQdcwvbv////8dYf8sbP9smP/09/8qaf/V4f8iZf/u8/+lwP+duv+UtP+PsP9hkP92n/9nlP/K2v/F1v+7z/+Ytv9Wif9Aef91nv9e7pgKAAAACHRSTlMA+puT/PWHhQBB7XEAAACQSURBVBjTTY8JCsQwCEWdrjFm37p37n/LMdAJfSTgf4IoAPQf8fDpgek4N9NxnwQZJx0/w+UMNd/XV6nluqsBQbRp79Xqvd7ICBCuaHuElMJhdXEspMKGko/YA2LYXyKuiGt8Ca3rfwm052nbjILV1IyFBZFZck4xppwXQ8Srk2wQzXzcIBpDB8w0/vM4AfwACl4LKjajMX0AAAAASUVORK5CYII=" - }, putio:{ regex:/app\.put\.io/, url:"https://app.put.io/files", @@ -541,190 +428,190 @@ var disableUrl=[".torrentkitty.","bt.box.n0808.com"]; var manageLinksLang={}; var lang = navigator.appName=="Netscape"?navigator.language:navigator.userLanguage; + var config={}; + switch (lang){ + case "zh-CN": + case "zh-SG": + config={ + configure:"全载设置", + yyw:"115网盘", + baidu:"百度网盘", + furk:"Furk网盘", + seedr:"Seedr网盘", + pcloud:"Pcloud网盘", + xunlei:"迅雷离线", + xunleipan:"迅雷网盘", + xiaomi:"小米路由器", + weiyun:"腾讯微云", + bitqiu:"比特球", + apiv:"九秒云播", + torrent:"Itorrents种子下载", + btcache:"Btcache.me种子下载", + enable:"启用", + disable:"禁用", + addIcon:"添加站点", + settingTitle:"全载", + urlRegexpTips:"自定义需要启用一键下载的链接正则,一行一条", + disableOnSite:"已于此站点禁用,点击启用", + bdPathTips:"不需要加'我的网盘/全部文件'", + bdPathTitle:"度盘存储路径:", + settingMouseOver:"仅当鼠标经过时显示图标", + settingBtn:"设置", + allDisableError:"不能全部禁用!", + siteRuleSetOK:"设置成功,刷新生效", + setOK:"设置成功", + regExpError:"含有无效正则,请重新输入", + addSiteRuleTitle:"自定义新增图标规则,一行一条", + siteRulePlaceholder:"站点 @@ 站名 @@ 下载链接正则 @@ 图标base64 @@ 图标背景颜色 @@ 是否隐藏图标\n\n@@ 分隔,目标站点中用 $url 代替目标链接,$hash 代表目标磁链的 hash 值,${reg}用正则提取,$text代表链接文本,$title代表链接title\n\n可用//注释规则\n\n例如:http://192.168.2.1/d2r?u=$url@@路由器下载\nhttp://xxx.com/magnet/$hash@@磁链下载@@^magnet@@data:image/png;base64,AAA@@ffffff", + inputLink:"输入需要离线下载的链接:", + importOrNot:"是否导入规则?", + importCustomAlert:"点击确定追加规则,点击取消覆盖规则", + importOver:"规则导入完毕!", + postOver:"发送成功,返回消息:", + copyOver:"复制成功!", + postError:"发送失败,错误内容:", + importCustomSame:"存在同名规则,是否覆盖?", + copyLinks:"嗅探下载资源", + noLinks:"当前页面没有资源!", + userName:"请输入用户账号", + userPass:"请输入用户密码", + seekKey:"嗅探快捷键:" + }; + manageLinksLang={ + copyAll:"全部复制", + copySel:"复制选中", + addTips:"%i代表递增 %n代表文件名", + sortByName:"按文件名排序", + sortByUrl:"按网址排序", + sortByType:"按扩展名排序", + preHolder:"批量前缀", + nextHolder:"批量后缀", + closeBtn:"关闭", + typeHead:"类型:" + }; + break; + case "zh-TW": + case "zh-HK": + case "zh-MO": + config={ + configure:"全載設置", + yyw:"115網盤", + baidu:"百度網盤", + furk:"Furk網盤", + seedr:"Seedr網盤", + pcloud:"Pcloud網盤", + xunlei:"迅雷離線", + xunleipan:"迅雷網盤", + xiaomi:"小米路由器", + weiyun:"騰訊微雲", + bitqiu:"比特球", + apiv:"九秒雲播", + torrent:"Itorrents種子下載", + btcache:"Btcache.me種子下載", + enable:"啟用", + disable:"禁用", + addIcon:"添加站點", + settingTitle:"全載", + urlRegexpTips:"自定義需要啟用一鍵下載的連結正則,一行一條", + disableOnSite:"已於此站點禁用,點擊啟用", + bdPathTips:"不需要加'我的網盤/全部文件'", + bdPathTitle:"度盤存儲路徑:", + settingMouseOver:"僅當滑鼠經過時顯示圖標", + settingBtn:"設置", + allDisableError:"不能全部禁用!", + siteRuleSetOK:"設置成功,刷新生效", + setOK:"設置成功", + regExpError:"含有無效正則,請重新輸入", + addSiteRuleTitle:"自定義新增圖標規則,一行一條", + siteRulePlaceholder:"站點 @@ 站名 @@ 下載鏈接正則 @@ 圖標base64 @@ 圖標背景顏色 @@ 是否隱藏圖標\n\n@@ 分隔,目標站點中用 $url 代替目標連結,$hash 代表目標磁鏈的 hash 值,${reg}用正则提取,$text代表連結文本,$title代表連結title\n\n可用//注釋規則\n\n例如:http://192.168.2.1/d2r?u=$url@@路由器下載\nhttp://xxx.com/magnet/$hash@@磁鏈下載@@^magnet@@data:image/png;base64,AAA@@ffffff", + inputLink:"輸入需要離線下載的連結:", + importOrNot:"是否導入規則?", + importCustomAlert:"點擊確定追加規則,點擊取消覆蓋規則", + importOver:"規則導入完畢!", + postOver:"發送成功,返回消息:", + copyOver:"複製成功!", + postError:"發送失敗,錯誤内容:", + importCustomSame:"存在同名規則,是否覆蓋?", + copyLinks:"嗅探下載資源", + noLinks:"當前頁面沒有資源!", + userName:"請輸入用戶賬號", + userPass:"請輸入用戶密碼", + seekKey:"嗅探快捷鍵:" + }; + manageLinksLang={ + copyAll:"全部複製", + copySel:"複製選中", + addTips:"%i代表遞增 %n代表文件名", + sortByName:"按文件名排序", + sortByUrl:"按網址排序", + sortByType:"按擴展名排序", + preHolder:"批量前綴", + nextHolder:"批量後綴", + closeBtn:"關閉", + typeHead:"類型:" + }; + break; + default: + config={ + configure:"Easy-Offline Configure", + yyw:"115", + baidu:"BaiduPan", + furk:"Furk", + seedr:"Seedr", + pcloud:"Pcloud", + xunlei:"Xunlei", + xunleipan:"XunleiPan", + xiaomi:"MiWifi", + weiyun:"Weiyun", + bitqiu:"bitqiu", + apiv:"Apiv Online play", + torrent:"Torrent download in itorrent.org", + btcache:"Torrent download in btcache.me", + enable:"Enable ", + disable:"Disable ", + addIcon:"Add new site", + settingTitle: "Easy Offline", + urlRegexpTips: "Customize the Link Regexp, one per line", + disableOnSite: "Disabled currently, click to enable", + bdPathTips: "No need to add'/all files'", + bdPathTitle: "Path of BDpan:", + settingMouseOver: "Display the icon only when the mouse passes over", + settingBtn: "Save", + allDisableError: "Cannot disable all!", + siteRuleSetOK: "Set successfully, refresh takes effect", + setOK: "Set successfully", + regExpError: "Contains invalid regularity, please re-enter", + addSiteRuleTitle: "Customize new icon rules, one per line", + siteRulePlaceholder: "site @@ sitename @@ link regexp @@ icon base64 @@ icon background color @@ hide icon\n\nUse @@ to separated, use $url for the target Link, $hash for the hash of the target magnet link, ${reg} for regexp result on link, $text for link text, $title for link title\n\nUse // to comment rule\n\nFor example: http://192.168.2.1/d2r?u=$url@@MyRouter\nhttp://xxx.com/magnet/$hash@@MyMagnetLinkDownload@@^magnet@@data:image/png;base64,AAA@@ffffff", + inputLink: "Enter the link that needs to be downloaded with this:", + importOrNot:"Do you want to import rules?", + importCustomAlert:"Ok to add rule,Cancel to cover rule", + importOver:"Rules import over!", + postOver:"Post over, return: ", + copyOver:"Copy over!", + postError:"Fail in post, error: ", + importCustomSame:"Rule exists, overwritten?", + copyLinks:"Seek downloadable links", + noLinks:"No links!", + userName:"Input user name", + userPass:"Input user pass", + seekKey:"Seek key: " + }; + manageLinksLang={ + copyAll: "Copy all", + copySel: "Copy selected", + addTips: "%i means increment, %n means file name", + sortByName: "Sort by name", + sortByUrl: "Sort by URL", + sortByType: "Sort by type", + preHolder: "Batch Prefix", + nextHolder: "Batch Suffix", + closeBtn: "Close", + typeHead: "Type:" + }; + break; + } var i18n=(name)=>{ - var config={}; - switch (lang){ - case "zh-CN": - case "zh-SG": - config={ - configure:"全载设置", - yyw:"115网盘", - baidu:"百度网盘", - furk:"Furk网盘", - seedr:"Seedr网盘", - pcloud:"Pcloud网盘", - xunlei:"迅雷离线", - xunleipan:"迅雷网盘", - xiaomi:"小米路由器", - weiyun:"腾讯微云", - bitqiu:"比特球", - apiv:"九秒云播", - torrent:"Itorrents种子下载", - btcache:"Btcache.me种子下载", - enable:"启用", - disable:"禁用", - addIcon:"添加站点", - settingTitle:"全载", - urlRegexpTips:"自定义需要启用一键下载的链接正则,一行一条", - disableOnSite:"已于此站点禁用,点击启用", - bdPathTips:"不需要加'我的网盘/全部文件'", - bdPathTitle:"度盘存储路径:", - settingMouseOver:"仅当鼠标经过时显示图标", - settingBtn:"设置", - allDisableError:"不能全部禁用!", - siteRuleSetOK:"设置成功,刷新生效", - setOK:"设置成功", - regExpError:"含有无效正则,请重新输入", - addSiteRuleTitle:"自定义新增图标规则,一行一条", - siteRulePlaceholder:"站点 @@ 站名 @@ 下载链接正则 @@ 图标base64 @@ 图标背景颜色 @@ 是否隐藏图标\n\n@@ 分隔,目标站点中用 $url 代替目标链接,$hash 代表目标磁链的 hash 值,${reg}用正则提取,$text代表链接文本,$title代表链接title\n\n可用//注释规则\n\n例如:http://192.168.2.1/d2r?u=$url@@路由器下载\nhttp://xxx.com/magnet/$hash@@磁链下载@@^magnet@@data:image/png;base64,AAA@@ffffff", - inputLink:"输入需要离线下载的链接:", - importOrNot:"是否导入规则?", - importCustomAlert:"点击确定追加规则,点击取消覆盖规则", - importOver:"规则导入完毕!", - postOver:"发送成功,返回消息:", - copyOver:"复制成功!", - postError:"发送失败,错误内容:", - importCustomSame:"存在同名规则,是否覆盖?", - copyLinks:"嗅探下载资源", - noLinks:"当前页面没有资源!", - userName:"请输入用户账号", - userPass:"请输入用户密码", - seekKey:"嗅探快捷键:" - }; - manageLinksLang={ - copyAll:"全部复制", - copySel:"复制选中", - addTips:"%i代表递增 %n代表文件名", - sortByName:"按文件名排序", - sortByUrl:"按网址排序", - sortByType:"按扩展名排序", - preHolder:"批量前缀", - nextHolder:"批量后缀", - closeBtn:"关闭", - typeHead:"类型:" - }; - break; - case "zh-TW": - case "zh-HK": - case "zh-MO": - config={ - configure:"全載設置", - yyw:"115網盤", - baidu:"百度網盤", - furk:"Furk網盤", - seedr:"Seedr網盤", - pcloud:"Pcloud網盤", - xunlei:"迅雷離線", - xunleipan:"迅雷網盤", - xiaomi:"小米路由器", - weiyun:"騰訊微雲", - bitqiu:"比特球", - apiv:"九秒雲播", - torrent:"Itorrents種子下載", - btcache:"Btcache.me種子下載", - enable:"啟用", - disable:"禁用", - addIcon:"添加站點", - settingTitle:"全載", - urlRegexpTips:"自定義需要啟用一鍵下載的連結正則,一行一條", - disableOnSite:"已於此站點禁用,點擊啟用", - bdPathTips:"不需要加'我的網盤/全部文件'", - bdPathTitle:"度盤存儲路徑:", - settingMouseOver:"僅當滑鼠經過時顯示圖標", - settingBtn:"設置", - allDisableError:"不能全部禁用!", - siteRuleSetOK:"設置成功,刷新生效", - setOK:"設置成功", - regExpError:"含有無效正則,請重新輸入", - addSiteRuleTitle:"自定義新增圖標規則,一行一條", - siteRulePlaceholder:"站點 @@ 站名 @@ 下載鏈接正則 @@ 圖標base64 @@ 圖標背景顏色 @@ 是否隱藏圖標\n\n@@ 分隔,目標站點中用 $url 代替目標連結,$hash 代表目標磁鏈的 hash 值,${reg}用正则提取,$text代表連結文本,$title代表連結title\n\n可用//注釋規則\n\n例如:http://192.168.2.1/d2r?u=$url@@路由器下載\nhttp://xxx.com/magnet/$hash@@磁鏈下載@@^magnet@@data:image/png;base64,AAA@@ffffff", - inputLink:"輸入需要離線下載的連結:", - importOrNot:"是否導入規則?", - importCustomAlert:"點擊確定追加規則,點擊取消覆蓋規則", - importOver:"規則導入完畢!", - postOver:"發送成功,返回消息:", - copyOver:"複製成功!", - postError:"發送失敗,錯誤内容:", - importCustomSame:"存在同名規則,是否覆蓋?", - copyLinks:"嗅探下載資源", - noLinks:"當前頁面沒有資源!", - userName:"請輸入用戶賬號", - userPass:"請輸入用戶密碼", - seekKey:"嗅探快捷鍵:" - }; - manageLinksLang={ - copyAll:"全部複製", - copySel:"複製選中", - addTips:"%i代表遞增 %n代表文件名", - sortByName:"按文件名排序", - sortByUrl:"按網址排序", - sortByType:"按擴展名排序", - preHolder:"批量前綴", - nextHolder:"批量後綴", - closeBtn:"關閉", - typeHead:"類型:" - }; - break; - default: - config={ - configure:"Easy-Offline Configure", - yyw:"115", - baidu:"BaiduPan", - furk:"Furk", - seedr:"Seedr", - pcloud:"Pcloud", - xunlei:"Xunlei", - xunleipan:"XunleiPan", - xiaomi:"MiWifi", - weiyun:"Weiyun", - bitqiu:"bitqiu", - apiv:"Apiv Online play", - torrent:"Torrent download in itorrent.org", - btcache:"Torrent download in btcache.me", - enable:"Enable ", - disable:"Disable ", - addIcon:"Add new site", - settingTitle: "Easy Offline", - urlRegexpTips: "Customize the Link Regexp, one per line", - disableOnSite: "Disabled currently, click to enable", - bdPathTips: "No need to add'/all files'", - bdPathTitle: "Path of BDpan:", - settingMouseOver: "Display the icon only when the mouse passes over", - settingBtn: "Save", - allDisableError: "Cannot disable all!", - siteRuleSetOK: "Set successfully, refresh takes effect", - setOK: "Set successfully", - regExpError: "Contains invalid regularity, please re-enter", - addSiteRuleTitle: "Customize new icon rules, one per line", - siteRulePlaceholder: "site @@ sitename @@ link regexp @@ icon base64 @@ icon background color @@ hide icon\n\nUse @@ to separated, use $url for the target Link, $hash for the hash of the target magnet link, ${reg} for regexp result on link, $text for link text, $title for link title\n\nUse // to comment rule\n\nFor example: http://192.168.2.1/d2r?u=$url@@MyRouter\nhttp://xxx.com/magnet/$hash@@MyMagnetLinkDownload@@^magnet@@data:image/png;base64,AAA@@ffffff", - inputLink: "Enter the link that needs to be downloaded with this:", - importOrNot:"Do you want to import rules?", - importCustomAlert:"Ok to add rule,Cancel to cover rule", - importOver:"Rules import over!", - postOver:"Post over, return: ", - copyOver:"Copy over!", - postError:"Fail in post, error: ", - importCustomSame:"Rule exists, overwritten?", - copyLinks:"Seek downloadable links", - noLinks:"No links!", - userName:"Input user name", - userPass:"Input user pass", - seekKey:"Seek key: " - }; - manageLinksLang={ - copyAll: "Copy all", - copySel: "Copy selected", - addTips: "%i means increment, %n means file name", - sortByName: "Sort by name", - sortByUrl: "Sort by URL", - sortByType: "Sort by type", - preHolder: "Batch Prefix", - nextHolder: "Batch Suffix", - closeBtn: "Close", - typeHead: "Type:" - }; - break; - } return config[name]?config[name]:name; }; @@ -868,24 +755,29 @@ defaultReg=new RegExp(defaultReg, 'i'); addCustomSites(()=>{ storage.getItem("siteSort",v=>{ - siteSort=v; - if(!siteSort)siteSort=["baidu","yyw","furk","seedr"]; - siteSort.forEach(function(item) { - var siteConfig=sites[item]; - if(siteConfig){ - siteConfig.name=item; + setTimeout(() => { + if (_unsafeWindow.eoAddons) { + sites = Object.assign(sites, _unsafeWindow.eoAddons); + } + siteSort=v; + if(!siteSort)siteSort=["baidu","yyw","furk","seedr"]; + siteSort.forEach(function(item) { + var siteConfig=sites[item]; + if(siteConfig){ + siteConfig.name=item; + sitesArr.push(siteConfig); + } + }); + for(let siteName in sites){ + let hasSite=false; + siteSort.forEach(function(item){if(item==siteName)hasSite=true;}); + if(hasSite)continue; + var siteConfig=sites[siteName]; + siteConfig.name=siteName; sitesArr.push(siteConfig); } - }); - for(let siteName in sites){ - let hasSite=false; - siteSort.forEach(function(item){if(item==siteName)hasSite=true;}); - if(hasSite)continue; - var siteConfig=sites[siteName]; - siteConfig.name=siteName; - sitesArr.push(siteConfig); - } - pageRun(); + pageRun(); + }, 1); }); }); }); @@ -1317,12 +1209,13 @@ if(/^c:/.test(url)){ urlArr.push(url.replace(/^c:/i,"")); }else if(/^p:/.test(url)){ - url=url.match(/p:(.*?)\?(.*)/); + url=url.match(/p:(.*?)\?(.*?)(\$headers({.*}))?$/); if(!url)return; let postData=JSON.stringify(urlArgs(url[2])); + let headers = url[4] ? JSON.parse(url[4]) : null; url=url[1]; _GM_xmlhttpRequest({ - method: "POST", url: url, data: postData, + method: "POST", url: url, data: postData, headers: headers, onload: (d) => { _GM_notification(i18n("postOver")+d.statusText); }, @@ -1351,12 +1244,13 @@ _GM_setClipboard(url.replace(/^c:/i,"")); _GM_notification(i18n("copyOver")); }else if(/^p:/.test(url)){ - url=url.match(/p:(.*?)\?(.*)/); + url=url.match(/p:(.*?)\?(.*?)(\$headers({.*}))?$/); if(!url)return; let postData=JSON.stringify(urlArgs(url[2])); + let headers = url[4] ? JSON.parse(url[4]) : null; url=url[1]; _GM_xmlhttpRequest({ - method: "POST", url: url, data: postData, + method: "POST", url: url, data: postData, headers: headers, onload: (d) => { _GM_notification(i18n("postOver")+d.statusText); }, @@ -1528,7 +1422,7 @@ document.body.appendChild(configContent); configContent.innerHTML=`
http://aria.hoothin.com/#!/new/$base64@@Aria2@@@@data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABOFBMVEUAAADSVF7SVF7SVF7LVWDSVF7QVF/SVF7SVF7SVF7SVF7SVF7SVF7RVF7SVF7SVF7SVF7SVF7SVF7SVF7SVF7SVF7SVF5ma4Di4uLSVF7v7+9DQ0NvaX1+ZniUYXGtXGppan+cYG+TYXLs7OyyW2h4tsiVlJWxs7ylpaWgoKBwaX2JZHVRVFxNT1VNTU1KSkxGRkd0uMzKysp5tceHipjDV2JYWFrr5ufa2tvT09Pjycu9v8a5u8PCwsK+vr6rrbego6+Tp62pqamZnKmloaGjj5l5fY+MfY60gozDfIa3foJkaHzTX2hYW2i6UVluSEuK2/Pd3d7X0NLExcm1tbWRlKKbm5uohJCOjo6GhoqOeInPgIh0coV8fHx7e3vRbXbObXaNY3SgX25hYmRhYWHJVmGOTFGNTFENIl9FAAAAF3RSTlMAJNEM+vr1iQjpyFfr6pybmjLusJhyIzaw7jcAAAHlSURBVDjLfZNnU+NADIbXduyQBBLq2fK6JcQmF0gvtOOOztGv90Ln//8Ddm3txkNmeD54vNI7klYrkRFaYT6f0/Vcfr6gkXGUklH13HoQ1F2vapSUZ+6JbKbsmIzvR/zrlDPZibT/lerXTc4fuDJj6r6aCjKTq5gJZwDH+FvJzcj0U8to/A+M93hYnlIwv+qh6RhijkQMNakj66PhF8BBr3cAZwEa/GxcYMbB8284CT90whOZxMnwJKUyHvurG/thpxPub3wykXKR9c8QATZtu7YT9nZqlvVVhDA0Uqji4XDVtrdeM95a1uYhGqsFMi2usGfb9uJWrcb81toeGr1pknfxf8nmLFox79Do5smkKOFNWrAkipgkevCSINBRMJ5CCmSK7ZTg47ZMMSqyHwt+fOOCbl8WObrm0OKC4R0X7A5PxTVlo87pFy5oNrngLz0XjZKtXqH/uIBSLmjRhmw1KSaP1WIuIdiltCUfiyjJc7cp/bm2vt5qd7ufbylt43OPBoayqFEUNZtRZJ42KE0GBkeuwgUr7FIAl5cArHWNdjxyWmpomd+8AXh8ALjmNcuhTY/9AODiAsCXYy9RVN/hGRLuXVafWJz06nmAeLh6z5d3AMjAKCpkHG1hTp3V9Vl1biG1/k8fR16xKi9r1wAAAABJRU5ErkJggg==@@ff2a00*之所以把Aria2做成自定義是因為每個人的Aria2UI網址都不一樣,用我的伺服器管理本地的Aria2服務需要允許Chrome訪問本地資源,訪問 chrome://flags/#block-insecure-private-network-requests 並關閉即可。不想關閉的話直接打開設置把上面的網址換成自己本地的即可,例如 127.0.0.1 -### 自定義例子3 - Post請求RPC遠程下載 +### 自定義例子3 - Post 請求 RPC 遠程下載
p:http://192.168.32.1:6800/jsonrpc?id=$random&jsonrpc=2.0&method=aria2.addUri¶ms=["token:123456",["$url"]]@@Aria2RPC@@@@@@df2a00@@ -68,6 +68,11 @@ https://translate.google.com/?client=gtx&dj=1&q=$text&sl=auto&tl=zh-CN&hl=zh-CN& $text{[^\w\-_\.~!\*'();:@&=\+\$,\/\?#\[\]%]}@@GetLink@@@@@@f9ff9f +### 自定義例子7 - Post 請求 OpenList(原AList)遠程下載 +
+p:https://alist.domain.com/api/fs/add_offline_download?path=/115网盘/OpList离线下载&tool=115%20Cloud&delete_policy=delete_on_upload_succeed&urls=["$url"]$headers{"Content-Type": "application/json","Authorization": "alist-50a563b4-and-more-token-chars", "Accept": "*/*", "Host": "alist.domain.com", "Connection": "keep-alive"}@@OpenList@@@@@@df2a11
+
+
### Update
- **`Alt + F9`** 自定義下載,選中文本超鏈則下載文本超鏈,鼠標指向鏈接則下載鏈接,沒有選中則彈框輸入鏈接下載
diff --git a/FlashViewer-HTML5 Video/README.md b/FlashViewer-HTML5 Video/README.md
index f066f20599a..94771d645c5 100644
--- a/FlashViewer-HTML5 Video/README.md
+++ b/FlashViewer-HTML5 Video/README.md
@@ -1,4 +1,4 @@
-# [FlashViewer](https://github.com/hoothin/UserScripts/raw/master/FlashViewer-HTML5%20Video/flashViewer.user.js)
+# [FlashViewer⬇️](https://hoothin.github.io/UserScripts/FlashViewer-HTML5%20Video/flashViewer.user.js)
HTML5 視頻增強腳本
原作者 NLF
diff --git a/FlashViewer-HTML5 Video/flashViewer.user.js b/FlashViewer-HTML5 Video/flashViewer.user.js
index f82c580a9d9..e3f508f5e90 100644
--- a/FlashViewer-HTML5 Video/flashViewer.user.js
+++ b/FlashViewer-HTML5 Video/flashViewer.user.js
@@ -2,9 +2,9 @@
// @name flashViewer
// @author NLF & Hoothin
// @description 围观Flash,增加 HTML5 视频速度与亮度调整
-// @version 1.2.1.8
+// @version 1.2.1.9
// @created 2013-12-27
-// @lastUpdated 2023-8-16
+// @lastUpdated 2025-9-24
// @grant none
// @run-at document-start
// @namespace http://userscripts.org/users/NLF
@@ -190,17 +190,17 @@
position: relative !important;
z-index: auto !important;
opacity: 1 !important;
-
+
}
#playBox {
z-index: auto !important;
}
*/
}).cssText,
-
+
},
];
-
+
// 用到的图标
var icons = {
// 浮动工具栏
@@ -219,9 +219,9 @@
restore: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0MjFERUVEODNBNzFFMzExOTZFOUJBOUM1MDc0MDBFNiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo5MzBCNUQyMTcyRjMxMUUzOTM2RTg4MTQyQUEyRDU1MiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5MzBCNUQyMDcyRjMxMUUzOTM2RTg4MTQyQUEyRDU1MiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAyQkY0RjY0NUM3MUUzMTE5MEQ3RTAwRDBEMUUxQUQ5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjQyMURFRUQ4M0E3MUUzMTE5NkU5QkE5QzUwNzQwMEU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+KuIDRQAAAPpJREFUeNpi+P//PwM1ACPIIEZGRmxyc4FYCU3sHhAnk2TQwoUL34mJiQkii7169ep9fHy8EDaDmBioBEYNoqNBLEhsbyCOhnH+/v3Liq4YKrYMSWgpEG9FSUfbt29P+fnzZ9OXL18EQBICAgLszMzMTGgG/fvw4cNPEJubm/sjBwdHraen5xyMBAk0LB7InwXks+HzBlDNL6CadKAhC3CmbKBhNkCxjUAxIRyGvAPK+QMNOUIwiwANUwaKbwaKa6IZcgMo5gM05C7ReQ1oGD9QbjVQzhVqyG4gOxRoyEdScz/IMFCs9oPUAXEB0JA/+AKOOgmJWgYBBBgAo+l8rgH6VgYAAAAASUVORK5CYII=',
close: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDozMTNFNTRGM0VGNzJFMzExQTk3OEU1QTlDRTYyMTQxMSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1QzU4MzJGMTg4QjkxMUUzOTk4NzlCNUFFM0FFQkRBMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1QzU4MzJGMDg4QjkxMUUzOTk4NzlCNUFFM0FFQkRBMSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjNEMkFFNjFBOEU4OEUzMTFCNkY5QkM5REQ2QTE1QUNEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjMxM0U1NEYzRUY3MkUzMTFBOTc4RTVBOUNFNjIxNDExIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+gwuo4wAAAahJREFUeNpi/P//PwM1ABMDtQA1XAQygwWJnwbEkUj8WUC8HE1PBBCnI/FXAPFMEANu0Pbt25WAlAOMv2bNGtm5c+e+BjL3QIVckpKSWkJDQ5WRDDrl6emJEUaVQCcug3GCg4OV/f39+4FMKyC2BLFDQkKUkbwDUlsB4zOC/MfIyAhzFdu/f//WMTExeYP4f//+/Tdx4sQLIDUFBQUGzMzMYIuBarYB1QQCXfMLFkYoBkEN4wIacBCoyQTE//37918QzcrKygw1/AxQzh5oyDfkwMYwCGqY6K9fv46ysbGpIosDxe4AxayAhrxGjzWs6Qjk5I6Ojpvo4kCxG0C538QmSHZxcfH+lJQUR3QJkJiEhAQoAtgJGcTCy8vb3NjYGCwlJcUNdfYPEAaxQWINDQ1BIDXISQfdIEZ2dvaq2traRHl5eT6oIX+A4RcOwiA2SAwkB1LDyclZBdKDYRAwOlOrqqqydHV1RWBhCDQgARgmm0AYxAaJgSRAaioqKrJAejAM2rp1q6KZmZk4kgurgAYsRYoAELsKxgepBemhTaalhmFUK48AAgwALD+0S2sZwIQAAAAASUVORK5CYII=',
},
-
+
};
-
+
// 第一时间备份一些方法,防止被页面脚本覆盖掉
var nativeMethods = {
forEach: Array.prototype.forEach,
@@ -249,6 +249,20 @@
};
};
+
+ var escapeHTMLPolicy;
+ if (window.trustedTypes && window.trustedTypes.createPolicy) {
+ escapeHTMLPolicy=window.trustedTypes.createPolicy('pvcep_default', {
+ createHTML: (string, sink) => string,
+ createScriptURL: string => string,
+ createScript: string => string
+ });
+ }
+
+ function createHTML(html){
+ return escapeHTMLPolicy?escapeHTMLPolicy.createHTML(html):html;
+ }
+
//获取窗口大小.
function getWindowSize() {
/*
@@ -287,35 +301,35 @@
x: 'pageXOffset' in window ? window.pageXOffset : de.scrollLeft || body.scrollLeft,
y: 'pageYOffset' in window ? window.pageYOffset : de.scrollTop || body.scrollTop,
};
- };
-
+ };
+
// 事件支持检测.
// 比如 eventSupported('fullscreenchange', document);
function eventSupported(eventName, elem) {
elem = elem || document.createElement('div');
var prefix = ['o', 'ms', 'moz', 'webkit', ''];
-
+
var l = prefix.length;
var pEventName;
var isFunction;
var setAttr;
-
+
while(l --) {
pEventName = 'on' + prefix[l] + eventName;
-
+
if (pEventName in elem) {
return pEventName.slice(2);
- } else if (typeof elem.setAttribute == 'function') { // setAttribute 是元素节点的方法
+ } else if (typeof elem.setAttribute == 'function') { // setAttribute 是元素节点的方法
setAttr = false;
if (!elem.hasAttribute(pEventName)) {
setAttr = true;
elem.setAttribute(pEventName, 'return;');
};
-
+
isFunction = typeof elem[pEventName] == 'function';
-
+
if (setAttr) elem.removeAttribute(pEventName);
-
+
if (isFunction) {
return pEventName.slice(2);
};
@@ -329,7 +343,7 @@
// 在指定对象上保存数据
var data = (function () {
'use strict';
-
+
var cache = {
objs: [],
data: {},
@@ -350,7 +364,7 @@
return cache.data[id][key] = value;
};
};
-
+
return data;
})();
@@ -367,7 +381,7 @@
mouseleave : 'mouseout',
mouseenter : 'mouseover',
};
-
+
return {
add : function (type, ele, callback) { //事件类型,元素,监听函数
if (support[type]) {
@@ -385,7 +399,7 @@
};
data(callback, 'mouseELListener', listener);
};
-
+
ele.addEventListener(map[type], listener, true);
};
},
@@ -411,7 +425,7 @@
// console.log(matched);
ret[matched[1]] = matched[2];
};
-
+
return ret;
};
@@ -419,12 +433,12 @@
function cloneObject(obj, deep) {
var value;
var ret = Array.isArray(obj) ? [] : {};
-
+
for (var key in obj) {
if (!obj.hasOwnProperty(key)) continue;
-
+
value = obj[key];
-
+
if (value === obj) {// 引用自己
ret[key] = ret;
} else if (deep && (Array.isArray(value) || Object.prototype.toString.call(value) == '[object Object]')) {
@@ -441,7 +455,7 @@
// 比如proSupported('requestFullscreen');
function proSupported(proName, obj) {
obj = obj || document.createElement("div");
-
+
if (proName in obj)
return proName;
@@ -536,38 +550,38 @@
return false;
};
-
+
// 特性支持情况
var support = {
MutationObserver: proSupported('MutationObserver', window),
cssBoxSizing: cssProSupported('box-sizing'),
-
+
// 请求全屏
requestFullscreen: proSupported('requestFullscreen') || proSupported('requestFullScreen'),
// 返回当前页面是否允许全屏
fullscreenEnabled: proSupported('fullscreenEnabled', document) || proSupported('fullScreenEnabled', document),
// 返回当前全屏的元素,否则返回null
fullscreenElement: proSupported('fullscreenElement', document)
- || proSupported('fullScreenElement', document)
+ || proSupported('fullScreenElement', document)
|| proSupported('currentFullScreenElement', document),
// fullscreen 事件
fullscreenchange: eventSupported('fullscreenchange', document),
-
+
};
// console.log(support);
-
+
// fx库
var fx = (function () {
'use strict';
-
+
function $(selector, context) {
return new init(selector, context);
};
-
+
function init(selector, context) {
-
+
if (selector instanceof HTMLElement) { // 单个 html element 节点
[].push.call(this, selector);
return this;
@@ -581,22 +595,22 @@
unique.push(node);
};
});
-
+
[].push.apply(this, unique);
return this;
};
-
+
if (typeof selector == 'string') {// css字符串
if (!context || !context.nodeType || context.nodeType != 1) {// 不是元素节点的话,context指向document
context = document;
};
selector = context.querySelectorAll(selector); // NodeList
-
+
[].push.apply(this, selector);
return this;
};
-
- if (selector instanceof NodeList) {// NodeList
+
+ if (selector instanceof NodeList) {// NodeList
// 去除非元素节点
var elems = [];
each(selector, function () {
@@ -604,11 +618,11 @@
elems.push(this);
};
});
-
+
[].push.apply(this, elems);
return this;
};
-
+
if (selector instanceof HTMLCollection) { // HTMLCollection
[].push.apply(this, selector);
return this;
@@ -622,9 +636,9 @@
fn.call(elem);
});
};
-
+
init.prototype = {
-
+
animate: function (pros, opts) {
// 判断pros是否有属性
for (var pro in pros) {
@@ -632,30 +646,30 @@
break;
};
if (!pro) return this;
-
+
// 修正opts参数
if (!opts) {
opts = {};
};
-
+
// 动画持续时间
if (typeof opts.duration != 'number') {
opts.duration = 400;
};
-
+
// 动画算法
if (!opts.easing || !easing[opts.easing]) {
opts.easing = 'swing';
};
-
+
// 是否将动画放入队列
if (opts.queue !== false) {
opts.queue = true;
};
-
+
// 为每个属性指定特定的动画方法
opts.specialEasing = opts.specialEasing || {};
-
+
// 每个元素的所有属性动画完成之后都会调用
opts.complete = opts.complete || emptyFn;
// 封装complete
@@ -666,14 +680,14 @@
$(this).dequeue();
};
};
-
+
// 每个元素的每个属性的每一步都会调用
opts.step = opts.step || emptyFn;
-
-
+
+
return this[opts.queue ? 'queue' : 'each'](function () {
var elem = this;
-
+
// 复制pros对象
var prosC = cloneObject(pros);
// 复制opts对象
@@ -698,16 +712,16 @@
// 判断toggle是该执行show还是hide动画
if (value === 'toggle') {
value = isHidden ? 'show' : 'hide';
-
+
for (pro in prosC) {
if (!prosC.hasOwnProperty(pro)) continue;
prosC[pro] = value;
};
};
-
-
+
+
var style = elem.style;
-
+
var allAniData = [];
if (value === 'show') {// show操作
if (!isHidden) {
@@ -724,18 +738,18 @@
};
optsC.show = true;// 标记show操作
-
+
} else if (value === 'hide') {// hide操纵
if (isHidden) {
optsC.completeW.call(elem);
return;
};
-
+
optsC.hide = true;// 标记show操作
};
-
-
-
+
+
+
// 获取当前值
function getCur(pro) {
if (pro in style) {
@@ -744,7 +758,7 @@
return elem[pro];
};
};
-
+
var start;// 开始
var end;// 结束
var unit;// 单位
@@ -760,10 +774,10 @@
if (!prosC.hasOwnProperty(pro)) continue;
value = prosC[pro];
-
+
// 备份当前值,show或者hide操作的时候最后还原样式。
optsC.orig[pro] = style[pro];
-
+
if (value === 'show') {
start = 0;
end = parseFloat(cS[pro]);
@@ -783,10 +797,10 @@
if (parts) {
unit = parts[3];
end = parseFloat(parts[2]);
-
+
start = getCur(pro).toString();
parts2 = start.match(reg);
-
+
if (parts2) {
start = parseFloat(parts2[2]);
unit2 = parts2[3];
@@ -795,14 +809,14 @@
style[pro] = (end || 1) + unit;
start = ((end || 1) / parseFloat(getCur(pro))) * start;
};
-
+
if (parts[1]) {// +=/-=,做相对运行
end = ((parts[1] == "-=" ? -1 : 1) * end) + start;
};
};
};
};
-
+
if (typeof start == 'number' && typeof end == 'number' && typeof unit == 'string') {
allAniData.push([elem, pro, optsC, start, end, unit]);
// new FX(elem, pro, optsC).custom(start, end, unit);// 开始动画
@@ -810,39 +824,39 @@
optsC.curAnim[pro] = true;
};
};
-
+
// 等所有动画数据都获取完成后才开始动画,
// 否则对于show之类的操作,如果width先绘制第一帧设置width为0之后,容器会发生伸缩,导致height的可能获取不正确
allAniData.forEach(function (data) {
new FX(data[0], data[1], data[2]).custom(data[3], data[4], data[5]);
});
-
+
});
-
+
},
-
+
show: function (opts) {
return this.animate(genFx('show', {
o: true,
- v: true,
+ v: true,
h: true,
}), opts);
},
hide: function (opts) {
return this.animate(genFx('hide', {
- o: true,
- v: true,
+ o: true,
+ v: true,
h: true,
}), opts);
},
toggle: function (opts) {
return this.animate(genFx('toggle', {
- o: true,
- v: true,
+ o: true,
+ v: true,
h: true,
}), opts);
},
-
+
fadeIn: function (opts) {
return this.animate(genFx('show', {
o: true,
@@ -863,32 +877,32 @@
opacity: opacity,
}, opts);
},
-
+
slideDown: function (opts) {
return this.animate(genFx('show', {
- v: true,
+ v: true,
o: true,
}), opts);
},
slideUp: function (opts) {
return this.animate(genFx('hide', {
- v: true,
+ v: true,
o: true,
}), opts);
},
slideToggle: function (opts) {
return this.animate(genFx('toggle', {
- v: true,
+ v: true,
o: true,
}), opts);
},
-
+
// 立即停止当前动画
stop: function (clearQueue, jumpToEnd) {
if (clearQueue) {
this.clearQueue();
};
-
+
this.each(function () {
for (var i = timers.length - 1; i >= 0; i--) {
if (timers[i].elem == this) {//是当前元素的属性动画
@@ -902,13 +916,13 @@
if (!jumpToEnd) {
this.dequeue();
};
-
-
+
+
return this;
- },
+ },
clearQueue: function () {
this.queue([]);
-
+
return this;
},
delay: function (duration) {
@@ -919,67 +933,67 @@
}, duration);
});
},
-
-
+
+
each: function (fn) {
each(this, fn);
-
+
return this;
},
queue: function (fn, type) {
type = type || 'fx';
-
+
return this.each(function () {
-
+
// 取出队列
var q = data(this, type + 'queue');
if (!q) {// 初始化
q = [];
};
-
-
+
+
if (typeof fn == 'function') {
q.push(fn);
} else if (Array.isArray(fn)) { // array类型,直接覆盖掉
q = fn;
};
-
+
data(this, type + 'queue', q);
-
+
if (type == 'fx' && q.length == 1) { // 如果动画队列中只有自己,立即执行
q[0].call(this);
};
-
+
});
},
dequeue: function (type) {
type = type || 'fx';
-
+
return this.each(function () {
// 取出队列
var q = data(this, type + 'queue');
if (!q) {// 初始化
q = [];
};
-
+
q.shift();// 删除第一个
-
+
data(this, type + 'queue', q);
-
+
if (q[0]) {
q[0].call(this);
};
-
+
});
},
};
-
+
//对象克隆,接受{}和[]
function cloneObject(obj, deep) {
var value;
var ret = Array.isArray(obj) ? [] : {};
-
+
for (var key in obj) {
if (!obj.hasOwnProperty(key)) continue;
value = obj[key];
@@ -996,17 +1010,17 @@
function now() {
return Date.now();
};
-
+
// 空函数
function emptyFn() {
};
-
+
// 在指定对象上保存数据
var data = (function () {
'use strict';
-
+
var cache = {
objs: [],
data: {},
@@ -1027,17 +1041,17 @@
return cache.data[id][key] = value;
};
};
-
+
return data;
})();
-
+
var timers = [];
var aning = null;
- var requestAF = window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.msRequestAnimationFrame ||
+ var requestAF = window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
window.oRequestAnimationFrame;
// 算法
@@ -1055,9 +1069,9 @@
var pros = {
o: ['opacity',],
h: ['width', 'paddingLeft', 'paddingRight', 'borderLeftWidth', 'borderRightWidth', 'marginLeft', 'marginRight',],
- v: ['height', 'paddingTop', 'paddingBottom', 'borderTopWidth', 'borderBottomWidth', 'marginTop', 'marginBottom',],
+ v: ['height', 'paddingTop', 'paddingBottom', 'borderTopWidth', 'borderBottomWidth', 'marginTop', 'marginBottom',],
};
-
+
var ret = {};
for (var i in pros) {
if (!pros.hasOwnProperty(i)) continue;
@@ -1067,10 +1081,10 @@
});
};
};
-
+
return ret;
};
-
+
// 绘制动画
function draw() {
for ( var i = 0, l = timers.length; i < l; i++ ) {
@@ -1088,7 +1102,7 @@
};
};
-
+
// 每个属性创建一个FX实例
function FX(elem, pro, opts) {
// 配置
@@ -1098,28 +1112,28 @@
// 动画属性
this.pro = pro;
};
-
+
FX.off = false;// 关闭动画
-
+
FX.prototype = {
// 更新属性值
update: function () {
var pro = this.pro;
var elem = this.elem;
var opts = this.opts;
-
+
// 调用step函数,可以修改this对象
opts.step.call( elem, this.now, this );
-
+
var style = elem.style;
-
+
if (pro in style) {
if ((pro == 'height' || pro == 'width') && typeof opts.overflowX == 'undefined') {
opts.overflowX = style.overflowX;
opts.overflowY = style.overflowY;
style.overflow = 'hidden';
};
-
+
style[pro] = this.now + this.unit;
} else if (pro in elem) {
elem[pro] = this.now;
@@ -1128,14 +1142,14 @@
// 开启动画
custom: function (from, to, unit) {
this.startTime = now();//动画开始时间
-
+
this.start = from;//位置开始点
this.end = to;//位置结果点
-
+
this.unit = unit;// 单位
-
+
this.now = this.start;//位置当前点
-
+
//pos是按一定算法把时间上的比率折算到位置上的比率
//state是时间间隔在总的duration的比率
this.pos = this.state = 0;
@@ -1148,10 +1162,10 @@
return self.step(jumpToEnd);
};
t.elem = this.elem;//删除的时候做判断用
-
+
//timers栈是公共的,不同的元素的不同的属性step都是放在这里面。
timers.push(t);
-
+
if ( aning == null ) {
aning = true;
requestAF(draw);
@@ -1160,24 +1174,24 @@
},
step: function (jumpToEnd) {
var t = now();//运行到当前的时间
-
+
var opts = this.opts;
-
+
// 强行指定结束或当前时间大于startTime+duration
if (FX.off || jumpToEnd || t >= opts.duration + this.startTime ) {
this.now = this.end;//当前的位置为结束位置
this.pos = this.state = 1;//当前的state,pos的比率为1.最大。
this.update();//显示
-
+
//标识这个属性的动画已经完成
var curAnim = opts.curAnim;
curAnim[ this.pro ] = true;
-
+
//再一次判断是否这个元素的所有属性都已完成
var done = true;
for ( var i in curAnim ) {
if (!curAnim.hasOwnProperty(i)) continue;
-
+
if ( curAnim[i] !== true ) {
done = false;
break;
@@ -1186,7 +1200,7 @@
if ( done ) {
var style = this.elem.style;
-
+
if (opts.hide || opts.show) {
if (opts.hide) {
style.display = 'none';
@@ -1194,7 +1208,7 @@
style.setProperty('display', 'none', 'important');
};
};
-
+
// 还原css属性
var orig = opts.orig;
for (var i in orig) {
@@ -1202,21 +1216,21 @@
style[i] = orig[i];
};
};
-
+
if (typeof opts.overflowX != 'undefined') {
style.overflowX = opts.overflowX;
style.overflowY = opts.overflowY;
};
-
+
// 执行回调函数
opts.completeW.call( this.elem );
};
-
+
return false;
- };
-
-
+ };
+
+
var n = t - this.startTime;//时间间隔
this.state = n / opts.duration;//时间间隔比率
@@ -1228,29 +1242,29 @@
// 显示
this.update();
-
+
return true;
-
+
},
};
-
-
+
+
return $;
-
+
})();
-
-
+
+
var url = location.href;
-
-
+
+
// 重新初始化插件
function reinitPlugin(plugin) {
// 重载flash让参数生效
// chrome firefox 切换display none就能引发重载,ie不行。
// chrome firefox 删除后,添加进dom引发重载,ie不行
// chrome 切换常规流绝对定位流引发重载,ie不行
-
+
var pluNS = plugin.nextSibling;
var pluPN = plugin.parentNode;
pluPN.removeChild(plugin);
@@ -1263,7 +1277,7 @@
pluPN.appendChild(plugin);
};
}, 20);
-
+
/* var pStyle = plugin.style;
var oSDis = pStyle.display;
pStyle.display = 'none';
@@ -1278,7 +1292,7 @@
// 找到的插件统统由这个函数处理
function initializer(plugins) {
// console.log(plugins);
-
+
plugins.forEach(function (plugin) {
// plugin是否在已插入文档中
@@ -1289,7 +1303,7 @@
var src;
var type;
var isObject = plugin.nodeName == 'OBJECT';
-
+
if (isObject) {
if (plugin.hasAttribute('data')) {
src = plugin.data;
@@ -1297,11 +1311,11 @@
if (plugin.hasAttribute('type')) {
type = plugin.type;
};
-
+
if (src === undefined || type === undefined) {
nativeMethods.some.call(plugin.children, function (child){
if (child.nodeName != 'PARAM') return;
-
+
var key = child.name;
var value = child.value;
if (/^(?:src|movie)$/i.test(key)) {
@@ -1314,7 +1328,7 @@
};
});
};
-
+
type = type || '';
} else {// embed标签
src = plugin.src;
@@ -1325,7 +1339,7 @@
// 如果不存在src或者不是flash插件
if (!src || !/^(?:|application\/x-shockwave-flash)$/i.test(type)) return;
-
+
// 匹配到的规则
var matched;
rules.some(function (rule) {
@@ -1340,10 +1354,10 @@
var pFragment;
function addParamO(name, value) {
name = name.toLowerCase();
-
+
if (!nativeMethods.some.call(plugin.children, function (child) {
if (child.nodeName != 'PARAM') return;
-
+
if (child.name.toLowerCase() == name){
if (name == 'flashvars'){
child.value = gFlashVars(child.value, value);
@@ -1361,24 +1375,24 @@
pFragment = pFragment ? pFragment : document.createDocumentFragment();
pFragment.appendChild(param);
};
-
+
};
// 生成新的flashvars字符串
function gFlashVars(oValue, add) {
if (!oValue) return add;
if (!add) return oValue;
-
+
// 转成数组 ['a=1', 'b=2', 'c=']之类的形式
oValue = oValue.split('&');
add = add.split('&');
// 转成字典 {a:'1', b:'2', c:''}之类的形式
var oVDict = {};
-
+
function gDict(kv) {
if (!kv) return;
-
+
var index = kv.indexOf('=');
if (index == -1) {
if (kv !=' ') {
@@ -1390,11 +1404,11 @@
};
};
};
-
+
// 用新的值覆盖旧的值
oValue.forEach(gDict);
add.forEach(gDict);
-
+
// 转会字符串
var fVars = [];
for (var key in oVDict) {
@@ -1437,37 +1451,37 @@
addParamO('flashVars', fvs);
} else {
plugin.setAttribute('flashVars', gFlashVars(plugin.getAttribute('flashVars') || '', fvs));
-
+
};
};
if (pFragment) {
plugin.appendChild(pFragment);
};
-
+
// 标记已经修改
plugin.fvReInitialized = true;
-
+
reinitPlugin(plugin);
});
};
-
-
+
+
// 一些规则根据excludes强行设置enabled为false
rules.forEach(function (rule) {
if (rule.hasOwnProperty('excludes') && rule.excludes.test(url)) {
// console.log('根据excludes禁用规则', rule);
rule.enabled = false;
};
-
+
});
-
+
// 先处理脚本运行前已经加载的flash
initializer([].slice.call(document.querySelectorAll('object, embed'), 0));
-
-
+
+
// 建立一个监视事件,处理后来追加的插件
if(support.MutationObserver)
(new window[support.MutationObserver](function (mRecords) {
@@ -1485,26 +1499,26 @@
if (/^(?:OBJECT|EMBED)$/.test(node.nodeName)) {
wPlugins.push(node);
};
-
+
[].push.apply(wPlugins, node.querySelectorAll('object, embed'));
-
+
});
-
+
});
// console.log(wPlugins);
-
+
initializer(wPlugins);
})).observe(document, {
- childList: true,
- subtree: true,
+ childList: true,
+ subtree: true,
});
-
-
+
+
};
-
+
if (prefs.allowReinitFlash) {
// console.log(document.contentType);
// 修复firefox标签单独请求一个flash,加载本脚本后导致不能正常加载flash的问题
@@ -1514,8 +1528,8 @@
};
};
-
-
+
+
// --------------------------------------------
// 弹出视频
function PopVideo(video) {
@@ -1530,7 +1544,7 @@
PopVideo.timerId = null;
PopVideo.scrollFx = null;
PopVideo.topVideo = null;
-
+
PopVideo.prototype = {
lighting: true,
@@ -1539,26 +1553,103 @@
isFullscreen: false,
minWidth: 325,
minHeight: 150,
-
+
+ scale: function (e) {
+ if (this.pinned || this.maximized) return;
+ if (e.deltaY > 0) {
+ this.zoomLevel += -0.1;
+ if (this.zoomLevel > 3) this.zoomLevel = 1;
+ else if (this.zoomLevel < 0.1) this.zoomLevel = 0.1;
+ } else {
+ this.zoomLevel += 0.1;
+ if (this.zoomLevel < 0.5) this.zoomLevel = 1;
+ }
+ var oriSize = {
+ h: parseInt(this.vOriStyle.height),
+ w: parseInt(this.vOriStyle.width)
+ };
+ var afterSize = {
+ h: oriSize.h * this.zoomLevel || 10,
+ w: oriSize.w * this.zoomLevel || 10,
+ };
+ var controlLayerSize = {
+ h: parseInt(this.controlLayer.style.height),
+ w: parseInt(this.controlLayer.style.width)
+ };
+ var ratio = {
+ x: e.offsetX / controlLayerSize.w,
+ y: e.offsetY / controlLayerSize.h
+ };
+ this.controlLayer.style.width = afterSize.w + "px";
+ this.controlLayer.style.height = afterSize.h + "px";
+ this.controlLayer.style.top = parseInt(this.controlLayer.style.top) - (afterSize.h - controlLayerSize.h) * ratio.y + "px";
+ this.controlLayer.style.left = parseInt(this.controlLayer.style.left) - (afterSize.w - controlLayerSize.w) * ratio.x + "px";
+ e.preventDefault();
+ },
+
+ videoMouseDown: function (e) {
+ if (this.zoomLevel === 1) return;
+ e.stopPropagation();
+ let self = this, mousemoved = false;
+ let oriPos = {
+ x: parseInt(this.controlLayer.style.left),
+ y: parseInt(this.controlLayer.style.top)
+ };
+ let oriMouse = {
+ x: e.pageX,
+ y: e.pageY
+ };
+ let mouseupHandler = e => {
+ document.removeEventListener("mouseup", mouseupHandler);
+ document.removeEventListener("mousemove", mousemoveHandler);
+ if (mousemoved) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ };
+ let mouseclickHandler = e => {
+ document.removeEventListener("click", mouseclickHandler);
+ if (mousemoved) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ };
+ let mousemoveHandler = e => {
+ mousemoved = true;
+ self.controlLayer.style.top = oriPos.y + (e.pageY - oriMouse.y) + "px";
+ self.controlLayer.style.left = oriPos.x + (e.pageX - oriMouse.x) + "px";
+ e.preventDefault();
+ e.stopPropagation();
+ };
+ document.addEventListener("mouseup", mouseupHandler);
+ document.addEventListener("click", mouseclickHandler);
+ document.addEventListener("mousemove", mousemoveHandler);
+ },
+
init: function () {
this.addStyle();
-
+
var self = this;
-
+
var video = this.video;
this.vOriControls = video.controls;
var vNodeName = video.nodeName;
-
+
// 如果是这些元素,那么pin的时候直接用fixed方式(这些元素随便调整position不会引发重载)
- var fixedPin = /^(?:IFRAME|VIDEO|AUDIO)$/.test(vNodeName);
+ var fixedPin = /^(?:IFRAME|VIDEO|AUDIO|CANVAS)$/.test(vNodeName);
this.fixedPin = fixedPin;
-
+
video.fvPopVideo = true;// 标记弹出中。
-
+ this.zoomLevel = 1;
+ video.addEventListener("wheel", this.scale.bind(this));
+ if (vNodeName === "VIDEO") {
+ video.addEventListener("mousedown", this.videoMouseDown.bind(this), true);
+ }
+
// 很多网站加载flash为了兼容现代浏览器和ie,经常使用 object classid嵌套object或者embed的格式
var vPEIsObject;
var vCEIsPlugin;
-
+
if (/^(?:EMBED|OBJECT)$/.test(vNodeName)) {// object,embed标签
if ((vPEIsObject = video.parentElement) && vPEIsObject.nodeName == 'OBJECT') {// 弹出的是被嵌套的object或者embed
vPEIsObject.fvPopVideo = true;
@@ -1573,23 +1664,23 @@
} else if(/^(?:VIDEO|AUDIO)$/.test(vNodeName)) {// html5 video,audio标签
video.controls = true; // 显示播放控件
} else {// iframe 标签
-
+
};
-
+
// 创建创造关灯效果的黑色覆盖层
var fixedOverlayer = document.createElement('fvspan');
this.fixedOverlayer = fixedOverlayer;
fixedOverlayer.className = 'fv-p-v-light-off';
document.body.appendChild(fixedOverlayer);
-
+
// 创建控制video缩放的控制层,放在video的下面,但是在light层的上面
var controlLayer = document.createElement('fvspan');
this.controlLayer = controlLayer;
controlLayer.className = 'fv-p-v-control-layer';
- controlLayer.innerHTML = getMStr(function () {
+ controlLayer.innerHTML = createHTML(getMStr(function () {
var innerHTML;
/*
@@ -13,20 +13,101 @@ https://raw.githubusercontent.com/hoothin/UserScripts/master/Pagetual/pagetualRu
| Buy me a coffee if you get help💞 | +Buy me a coffee if you get help💞 | |||||||
|---|---|---|---|---|---|---|---|---|
PayPal | Ko-fi | 愛發電 |
- ![]() |
+ PayPal |
+ Ko-fi |
+ 愛發電 |
||
| 📧Send me an email | +Join 💬Discord | |||||||
| Made with ❤️ by Hoothin | +Follow 🕊️twitter | +|||||||
| Send 📧email | +||||||||
Made with ❤️ by Hoothin |
||||||||