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,12 +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 拼接即可
+```
+
++ [📕愛發電](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
@@ -193,6 +251,8 @@ function decode(t) {
預設是取章節連結文字為標題,可以在設定中自訂章節標題,輸入 title 即為抓取分頁頁面的標題,輸入 h1 即為抓取分頁頁面 h1 等級的文章標題
- 下載内容不全怎麽辦?
可能因爲頁内正文是動態加載的,可嘗試在設置頁勾選“下載前打開篩選窗口”,然後選中“使用 iframe 後臺加載内容”
+- 抓取失敗是因為?
+NETWORK ERROR 説明網路錯誤,可能是當前本機網路故障,也可能是被目標網站封鎖了 IP。 TIMEOUT 説明訪問超時,可能是因爲當前網路速率過慢或目標網站流量超限
- 其他問題歡迎透過 email 聯絡我,有空可幫你解決。
### 為啥要寫這個腳本?
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 it helps you💞 | +Buy me a coffee if you get help💞 | |||||||
|---|---|---|---|---|---|---|---|---|
PayPal | Ko-fi | 愛發電 |
- ![]() |
+ PayPal |
+ Ko-fi |
+ 愛發電 |
||
| 📧Send me an email for help | +Join 💬Discord | |||||||
| Made with ❤️ by Hoothin | +Follow 🕊️twitter | +|||||||
| Send 📧email | +||||||||
Made with ❤️ by Hoothin |
||||||||