久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

【輕松上手】油猴腳本開(kāi)發(fā)

 子杰吃大餅 2023-11-13 發(fā)布于中國(guó)香港

本文已參與「掘力星計(jì)劃」,,贏取創(chuàng)作大禮包,挑戰(zhàn)創(chuàng)作激勵(lì)金,。

注:本文的油猴特指 Tampermonkey,。

油猴腳本運(yùn)行于油猴插件之上,油猴插件本質(zhì)上對(duì)瀏覽器能力的再封裝,。既然如此,,我們先來(lái)簡(jiǎn)單了解一下瀏覽器插件。

瀏覽器插件(Browser Extension):瀏覽器的擴(kuò)展應(yīng)用

說(shuō)的直白一點(diǎn),就是拿著瀏覽器開(kāi)放的能力(插件 API),,去實(shí)現(xiàn)一些小型應(yīng)用,。

瀏覽器插件主要由四部分構(gòu)成:background scripts、content scripts,、全局 UI 元素,、options page。

  • background scrips: 后臺(tái)腳本,,一個(gè)后臺(tái)腳本是一個(gè)獨(dú)立線程,,是游離于各個(gè)頁(yè)面之外的“上帝之眼”。具有訪問(wèn)各類插件 API 的能力,,但同時(shí)也喪失了直接操作頁(yè)面的能力,;
  • content scripts:內(nèi)容腳本,具有直接操作頁(yè)面的能力,。其實(shí)就是在頁(yè)面中運(yùn)行 js 腳本,,可以使用 DOM API。content script 只能直接訪問(wèn)少量插件 API,,但能和 background script 進(jìn)行雙向通信完成數(shù)據(jù)交換,;
  • 全局 UI 元素:瀏覽器層的 UI 交互,包括
    • 在 Toolbar 顯示 icon,,定義點(diǎn)擊 icon 后顯示的 Popup 或其他效果
    • 增加右鍵選項(xiàng)
    • 增加全局快捷鍵
    • 改造新 Tab 頁(yè),、歷史記錄頁(yè)、書(shū)簽頁(yè)
  • options page:插件配置頁(yè)

瀏覽器插件的核心機(jī)制可以用下圖簡(jiǎn)單概括

50c4c582f8f1968c5699220d1c2fc0c99a1212a171bcefa37d1aecdaccbaed5e.png

想必,,大家最好奇的還是有哪些 API 以及能用這些 API 做什么,,這里例舉幾個(gè):

  • contextMenus:增加右鍵選項(xiàng)
    • 使用選中文本,例如:劃詞翻譯,、文本收集
    • 快速調(diào)用插件功能,,例如:打開(kāi) DevTool,頁(yè)面剪藏
  • cookies:增刪改查 cookie(任意域名),,直接拿著本地 cookie 發(fā)送請(qǐng)求,,不必再做授權(quán)。同時(shí)由于后臺(tái)腳本不是 Web 頁(yè)面,,在發(fā)送請(qǐng)求時(shí)沒(méi)有跨域限制,。:
    • 多平臺(tái)信息聚合
    • 多平臺(tái)信息分發(fā)
  • devtools.panels:增加 Devtool 面板,這個(gè)對(duì)前端開(kāi)發(fā)者來(lái)說(shuō)應(yīng)該很熟悉,,React Developer Tools,、Vue.js devtools
  • notifications:瀏覽器通知,未打開(kāi)頁(yè)面的情況下進(jìn)行通知,,可以輔助一些工具類應(yīng)用
  • storage:全局保存數(shù)據(jù),,可跟隨瀏覽器賬戶同步

這里例舉的只是我常用的一些,,只是滄海一粟,更多 API 可以查閱

瀏覽器插件就簡(jiǎn)單介紹到這里,,如果有興趣繼續(xù)了解,,推薦:ChromeEdge,,Mozilla 三家的文檔,。

油猴插件(Tampermonkey)

瀏覽器插件可以實(shí)現(xiàn)各式各樣的功能,但有時(shí)候開(kāi)發(fā)者只是想對(duì)某一個(gè)站點(diǎn)加一點(diǎn)點(diǎn)小功能,,如果這也要構(gòu)建環(huán)境打包上架分發(fā),,未免就太麻煩了一些;從應(yīng)用市場(chǎng)角度來(lái)看,,充斥著顆?;膽?yīng)用,市場(chǎng)也會(huì)擁擠繁雜不堪,。

油猴插件為輕量化腳本提供了一個(gè)平臺(tái),,在線編輯器中編寫油猴腳本即時(shí)生效,通過(guò) Github,、GreasyFork 快速分發(fā),。

在油猴插件中, content script 起到非常重要的角色,,它將用戶編寫的代碼運(yùn)行在頁(yè)面中,,同時(shí)提供 GM_xxxx 函數(shù)封裝瀏覽器的部分能力。封裝的內(nèi)部實(shí)現(xiàn)是和 background script 通信,,驅(qū)動(dòng) background script 調(diào)用插件 API,。

對(duì)油猴插件簡(jiǎn)單了解之后,來(lái)看看如何編寫油猴腳本,。

Tampermonkey API

油猴腳本由頭部和核心邏輯兩部分組成

// ==UserScript== // @name New Userscript // @namespace http:/// // @version 0.1 // @description try to take over the world! // @author You // @match https://www./documentation.php?ext=dhdg // @icon https://www.google.com/s2/favicons?domain= // @grant none // ==/UserScript== (function() { 'use strict'; // Your code here... })();

頭部是腳本的一些元信息,、更新方式、指定運(yùn)行頁(yè)面,、權(quán)限聲明,,逐一解釋一下

配置名作用使用技巧
@name腳本的顯示名稱加后綴實(shí)現(xiàn)國(guó)際化,例如,,@name:zh-CN 指定在瀏覽器語(yǔ)言為中文時(shí)顯示的名稱
@namespace腳本的命名空間,可以理解為腳本的標(biāo)識(shí)為了避免沖突一般使用 github 倉(cāng)庫(kù)地址
@version與更新相關(guān),,當(dāng)前版本
@updateURL檢查腳本是否更新地址配合 @version 和自動(dòng)更新使用
@downloadURL檢測(cè)到更新時(shí),,去哪下載腳本
@supportURL遇到問(wèn)題時(shí),用戶去哪反饋
@include腳本在哪些頁(yè)面運(yùn)行可使用正則,,不支持 hashtag,,多個(gè)頁(yè)面的地址聲明多個(gè) @include 即可
@match與 @include 類似
@exclude腳本禁止在哪些頁(yè)面運(yùn)行,,優(yōu)先于 @include
@require在腳本運(yùn)行前引入外部 JavaScript 文件例如,引入 jQuery
@resource聲明外部資源文件,,搭配 GM_getResourceText 使用例如引入 html,、icon
@connect聲明 GM_xmlhttpRequest 可訪問(wèn)的域必須指定才能正常請(qǐng)求
@grant聲明 GM_xxx 函數(shù)的使用列表必須先指定權(quán)限才能正常使用
@run-at指定腳本運(yùn)行時(shí)機(jī)document-start: 盡快執(zhí)行
document-body: 當(dāng) body 掛載時(shí)執(zhí)行
document-end: DOMContentLoaded 觸發(fā)時(shí)執(zhí)行
document-idle: DOMContentLoaded 觸發(fā)后執(zhí)行,也是默認(rèn)設(shè)置項(xiàng)
context-menu: 右鍵菜單項(xiàng)被點(diǎn)擊時(shí)執(zhí)行
@author作者名
@description簡(jiǎn)短介紹同樣可以加后綴實(shí)現(xiàn)國(guó)際化
@homepage主頁(yè)地址如果未設(shè)置并且 @namespace 是倉(cāng)庫(kù)地址,,默認(rèn)導(dǎo)向倉(cāng)庫(kù)地址
@icon腳本 icon
@icon6464x64像素的腳本 icon
@antifeature腳本是否有廣告,、挖礦、數(shù)據(jù)收集等商業(yè)行為
@noframes聲明腳本不在 iframe 中運(yùn)行

核心邏輯通過(guò)一個(gè)立即執(zhí)行函數(shù)包裹,,避免和全局作用域相互干擾,。Tampermonkey 將瀏覽器的部分能力封裝為 GM_XXX 函數(shù)以供調(diào)用。

API作用使用技巧
unsafeWindow訪問(wèn)頁(yè)面的 Window 對(duì)象
GM_addStyle(css)創(chuàng)建全局樣式的快捷方式,,向頁(yè)面插入 style 元素也可以用 DOM 操作手動(dòng)創(chuàng)建
GM_addElement(tag_name, attributes)
GM_addElement(parent_node, tag_name, attributes)
向 DOM 新建元素的快捷方式也可以用 DOM 操作手動(dòng)創(chuàng)建
GM_log(message)在 console 中打印信息console.log 的快捷方式
GM_setValue(name, value)持續(xù)化存儲(chǔ)數(shù)據(jù)
GM_getValue(name, defaultValue)從存儲(chǔ)體中獲取數(shù)據(jù)
GM_deleteValue(name)從存儲(chǔ)體中刪除數(shù)據(jù)
GM_listValues()列舉存儲(chǔ)體中所有數(shù)據(jù)項(xiàng)
GM_addValueChangeListener監(jiān)聽(tīng)數(shù)據(jù)更新例如要使 Tab 間數(shù)據(jù)同步,,可以用監(jiān)聽(tīng) value 達(dá)成同步
GM_removeValueChangeListener移除監(jiān)聽(tīng)
GM_getResourceText(name)獲取 @resource 中已聲明的資源
GM_getResourceURL(name)獲取 @resource 中已聲明的資源(base64 URI 形式)
GM_registerMenuCommand(name, fn, accessKey)在 Tampermonkey 的 popup 中增加選項(xiàng)
GM_unregisterMenuCommand(menuCmdId)移除選項(xiàng)
GM_openInTab(url, options)新開(kāi)一個(gè) tab 頁(yè)
GM_xmlhttpRequest(details)使用后臺(tái)腳本進(jìn)行請(qǐng)求,自動(dòng)帶上 cookie,,無(wú)跨域問(wèn)題,,目標(biāo)域需要在 @connect 中提前聲明
GM_download(details)下載資源到本地
GM_getTab(callback)獲取當(dāng)前 tab 的 object 對(duì)象
GM_saveTab(tab)通過(guò) tab 的 object 對(duì)象重新打開(kāi)一個(gè) tab
GM_getTabs(callback)獲取當(dāng)前存活的所有 tab 的對(duì)象,以便和其他腳本實(shí)例偶同學(xué)
GM_notification使用插件 notification API 彈出桌面通知
GM_setClipboard復(fù)制內(nèi)容到剪貼板
GM_info獲取腳本的油猴插件的信息

完整的說(shuō)明文檔:Tampermonkey documentation

實(shí)踐:打印 Hello, World

做一個(gè)非常簡(jiǎn)單的小練習(xí):創(chuàng)建一個(gè)名為 'Hello' 的腳本,,當(dāng)進(jìn)入掘金和知乎頁(yè)面時(shí),,在 Console 中打印 'Hello, World'。

image.png

  1. 新建腳本
  2. 修改腳本名稱
  3. 指定運(yùn)行地址 @match@include
  4. 直接使用 console.log 或者聲明權(quán)限調(diào)用 GM_log
// ==UserScript==
// @name         Hello
// @namespace    http:///hello
// @version      0.1
// @description  try to take over the world!
// @author       You Name
// @match        https://zhihu.com/*
// @match        https:///*
// @grant        GM_log
// ==/UserScript==

(function() {
    'use strict';
    GM_log('Hello World');
})();

搭建舒適的開(kāi)發(fā)環(huán)境

使用在線編輯器小試牛刀之后,,或許你也發(fā)現(xiàn)在線編輯器

  • 缺少語(yǔ)法補(bǔ)全和自動(dòng)提示
  • 難以格式化代碼

不免懷念起 VSCode,。

或許你還會(huì)有更深遠(yuǎn)的考慮,在線編輯器編輯完成后:

  • 怎么同步到遠(yuǎn)程倉(cāng)庫(kù),,怎么做代碼分發(fā)
  • 如果要用到新語(yǔ)法,,怎么保證跨瀏覽器兼容性
  • 如果代碼越寫越多,沒(méi)有模塊化怎么管理
  • 沒(méi)有 TS,,很難保證長(zhǎng)期維護(hù)

這些坑我已經(jīng)踩過(guò)了,,并且抽出一個(gè)腳手架工具 create-tampermonkey - npm (),一鍵搭建舒適的油猴腳本開(kāi)發(fā)環(huán)境,。

Screen Shot 2021-10-24 at 9.54.53 PM.png

腳手架集成 rollup + babel + eslint + typescript,,支持:

  • 自動(dòng)生成 UserScript Header
  • 語(yǔ)法和類型系統(tǒng):ESNext、ES Module,、TypeScript
  • 樣式系統(tǒng):CSS Modules,,以及 scss、sass,、less,、stylus(需安裝對(duì)應(yīng)依賴)
  • 靜態(tài)資源:導(dǎo)入圖片、SVG 轉(zhuǎn)換為 Base64,,同時(shí)支持 SVG Sprite
  • 多語(yǔ)言
  • 擴(kuò)展:基于 Rollup,,可以按需安裝插件進(jìn)行擴(kuò)展

create-tampermonkey 啟動(dòng)項(xiàng)目

初始化項(xiàng)目

npx create-tampermonkey demo-userscript 或者 npm init tampermonkey demo-userscript 或者 yarn create tampermonkey demo-userscript

初始化完畢后,,進(jìn)入目錄安裝依賴 Screen Shot 2021-10-24 at 9.54.53 PM.png

npm run dev 跑起開(kāi)發(fā)模式

Screen Shot 2021-10-24 at 10.07.27 PM.png

到瀏覽器中打開(kāi) dev.user.js,自動(dòng)進(jìn)入 Tampermonkey 腳本安裝界面

Screen Shot 2021-10-24 at 10.10.21 PM.png

最后一步:訪問(wèn) chrome://extension,,找到油猴插件的卡片,,點(diǎn)擊 Details 進(jìn)入配置界面

Screen Shot 2021-10-25 at 9.15.10 AM.png

勾選 Allow acess to file URLs

image.png

刷新頁(yè)面,出現(xiàn)彈窗,,一切就緒,。

Screen Shot 2021-10-24 at 10.12.15 PM.png

用 VSCode 打開(kāi)項(xiàng)目,這時(shí)右下角會(huì)推薦一些輔助插件,,建議安裝,。

代碼中使用到的 GM_xxx 會(huì)自動(dòng)提取到 UserScript Header 中,當(dāng)然也可以在 src/meta.json 中自定義,。

代碼的默認(rèn)入口是 src/main.js 文件,。

實(shí)踐:掘金簽到功能

基于上面初始化的項(xiàng)目 demo-userscript 做一個(gè)小功能:掘金簽到功能。

1. 定位請(qǐng)求

“掘金簽到”本質(zhì)是調(diào)用接口,,我們的實(shí)現(xiàn)思路是追蹤點(diǎn)擊“立即簽到”按鈕時(shí)請(qǐng)求發(fā)送情況,,定位到

Screen Shot 2021-10-24 at 10.21.16 PM.png

2. 調(diào)試接口

打開(kāi) Postman 做一下調(diào)試,這里有一個(gè)導(dǎo)入小技巧,。

右鍵拷貝 cURL

Screen Shot 2021-10-24 at 10.24.44 PM.png

到 Postman 中通過(guò) curl 導(dǎo)入整個(gè)請(qǐng)求:點(diǎn)擊左側(cè)面板中的 import 按鈕,,選擇 Raw text 粘貼上一步復(fù)制的內(nèi)容即可。

Screen Shot 2021-10-24 at 10.25.09 PM.png

3. 獲取參數(shù)

Screen Shot 2021-10-24 at 10.27.42 PM.png

在 Postman 中發(fā)現(xiàn)請(qǐng)求需要 aid,、uuid,、_signature 三個(gè)參數(shù),試試看不帶參數(shù)能否請(qǐng)求成功,,先確定好必不可少的參數(shù)和請(qǐng)求頭,。

簡(jiǎn)單嘗試后,發(fā)現(xiàn)這里并不需要帶 aid,、uuid,、_signature 三個(gè)參數(shù),主要是依賴 cookie,,使用 GM_xmlhttpRequest 會(huì)自動(dòng)帶上對(duì)應(yīng)的 cookie,,事情變得簡(jiǎn)單。

修改 src/main.js 的代碼

GM_xmlhttpRequest({
  url: 'https://api./growth_api/v1/check_in',
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    'user-agent': navigator.userAgent,
  },
  responseType: 'json',
  onload(response) {
    if (response.status === 200) {
      const data = response.response;
      if (data.data === 'success') {
        alert('簽到成功');
      } else {
        alert(data.err_msg);
      }
    }
  },
});

刷新頁(yè)面測(cè)試一下,。在其他站點(diǎn)刷新一下居然也可以發(fā)送請(qǐng)求,,這就是插件沒(méi)有跨域限制的優(yōu)勢(shì)了。

再做一下節(jié)流優(yōu)化,。利用 GM_setValueGM_getValue 做持續(xù)存儲(chǔ),。

const storageKey = 'last_sign_timestamp'; // 獲取上一次簽到的日子 const lastSignNumberOfDays = GM_getValue(storageKey, 0); // 計(jì)算現(xiàn)在所在的日子 const currentNumberOfDays = Math.floor( new Date().valueOf() / 1000 / 60 / 60 / 24 ); // 如果今天已經(jīng)請(qǐng)求過(guò),不再請(qǐng)求 if (currentNumberOfDays !== lastSignNumberOfDays) { GM_xmlhttpRequest({ url: 'https://api./growth_api/v1/check_in', method: 'POST', headers: { 'content-type': 'application/json', 'user-agent': navigator.userAgent, }, responseType: 'json', onload(response) { if (response.status === 200) { const data = response.response; if (data.data === 'success') { alert('簽到成功'); } else { alert(data.err_msg); } // 更新最近一次簽到的日子 GM_setValue(storageKey, currentNumberOfDays); } }, }); }

難免會(huì)遇到需要獲取數(shù)據(jù)的情況,可訪問(wèn)的數(shù)據(jù)一般有三種:

  1. 頁(yè)面中包含數(shù)據(jù),,通過(guò) DOM 獲取
  2. 通過(guò)接口請(qǐng)求得到
  3. 存儲(chǔ)在本地存儲(chǔ)中,localStorage 或 cookie 之類

確定方式很粗暴:

  1. 復(fù)制參數(shù)或參數(shù)值到 Element 中搜索,;
  2. 查看前面幾個(gè)請(qǐng)求,,看看是否有跡可循;
  3. 到 localStorage 或 cookie 中搜索,。

分發(fā)腳本

在本地開(kāi)發(fā)完腳本之后,,npm run build 構(gòu)建生產(chǎn)版本并上傳代碼到 Github 或 Gitee。

用 Github/Gitee 上文件的 Raw URL 就能直接實(shí)現(xiàn)分發(fā),。如果在 package.json 中設(shè)置好 repository,,create-tampermonkey 會(huì)自動(dòng)生成 Raw URL 并賦給downloadURLupdateURL,。

但這樣分發(fā)存在的問(wèn)題是無(wú)法統(tǒng)計(jì)下載量,、從網(wǎng)絡(luò)訪問(wèn)的角度考慮同時(shí)維護(hù) Github 和 Gitee 兩個(gè)倉(cāng)庫(kù)。另一種分發(fā)方式是上傳到腳本平臺(tái) / ,, 登錄后即可發(fā)布新腳本,,如果代碼托管在 Github 或 GitLab 還可以使用 Webhooks 實(shí)現(xiàn)自動(dòng)更新。

開(kāi)發(fā)技巧

調(diào)試油猴腳本

油猴腳本的運(yùn)行依托于 background scriptcontent script,,在調(diào)試前需要對(duì)運(yùn)行環(huán)境有所區(qū)分,,例如 GM_xmlhttpRequest 請(qǐng)求是 background script 發(fā)出的,DOM 處理和腳本邏輯是 content script 執(zhí)行的,。

確定環(huán)境之后,,就可以使用對(duì)應(yīng)的調(diào)試方式進(jìn)行調(diào)試了。

調(diào)試 background script

還是訪問(wèn) chrome://extension,,找到油猴插件的卡片

Screen Shot 2021-10-25 at 9.15.18 AM.png

inspect views 后面有個(gè) background.html,,點(diǎn)擊一下彈出 background script 的調(diào)試彈窗。

調(diào)試 content script

在網(wǎng)頁(yè) inspect -> Sources -> Page 下找到 Tampermonkey 目錄,,頁(yè)面中運(yùn)行的油猴腳本代碼都在這了,,選擇目標(biāo),斷點(diǎn)調(diào)試即可,。

image.png

獲取 userId 等信息

有時(shí)候需要拿一些額外信息做請(qǐng)求,,一般有三種方式:

  1. 看看能不能在頁(yè)面中搜索到,通過(guò) DOM 獲取
  2. 看看有沒(méi)有接口可以調(diào)用獲取
  3. 看看本地存儲(chǔ)里有沒(méi)有

目標(biāo) DOM 節(jié)點(diǎn)未掛載怎么辦,?

如果節(jié)點(diǎn)是在首屏加載的,,粗暴的方法是使用 setTimeout 做一下延時(shí)。

但如果是在交互過(guò)程中有 DOM 更新,,就只能引入監(jiān)聽(tīng)機(jī)制了,,使用 MutationObserver 來(lái)實(shí)現(xiàn)。

具體的實(shí)例可以看 【開(kāi)發(fā)記錄】掘金 “破圈行動(dòng)” 輔助腳本 - 掘金 ()

查看插件源碼

瀏覽器插件安裝之后,,插件包被下載到本地目錄中,,可通過(guò)下述方法訪問(wèn),。

訪問(wèn) chrome://version,找到 Profile path(存放用戶數(shù)據(jù)的路徑) image.png

訪問(wèn) chrome://extensions/,,找到目標(biāo)插件的 ID

image.png

將 Profile Path 和插件 ID 拼裝在一起 ${Prifile Path}/Extensions/${Extension Id},,便是插件包的路徑了。友情提示,,通過(guò)命令行訪問(wèn)時(shí)需要在空格前加個(gè) \ 轉(zhuǎn)義一下,。

總結(jié)

瀏覽器插件利用瀏覽器能力進(jìn)行功能擴(kuò)展,具有跨域請(qǐng)求,、讀取 cookie,、管理歷史記錄、注冊(cè)右鍵項(xiàng)等能力,。

瀏覽器插件的能力很豐富,,能夠?qū)崿F(xiàn)復(fù)雜的功能。但如果只是做一些針對(duì)頁(yè)面的操作,,只需要依賴基礎(chǔ)能力,,完全可以使用油猴腳本實(shí)現(xiàn),開(kāi)發(fā)更便捷分發(fā)更迅速,。

開(kāi)發(fā)油猴腳本,,主要是使用 Tampermonkey API 和 JavaScript。

create-tampermonkey 腳手架提供一個(gè)全面的油猴腳本開(kāi)發(fā)環(huán)境,,依托這個(gè)環(huán)境,,可以使用最新的 ES 語(yǔ)法、TypeScript,、CSS Modules,,在 VSCode 中進(jìn)行模塊化開(kāi)發(fā),大大提高開(kāi)發(fā)效率,。

開(kāi)發(fā)完畢的油猴腳本可通過(guò) Github/Gitee Raw URL 或 Greasy Fork 平臺(tái)分發(fā),。

瀏覽器插件的主要分工為 background scriptcontent script 兩部分,在調(diào)試油猴腳本時(shí)需要思考清楚是哪一部分出現(xiàn)的問(wèn)題,,再采用對(duì)應(yīng)的調(diào)試方式,。

實(shí)現(xiàn)了兩個(gè)小實(shí)踐,走出第一步,,接下來(lái)盡情發(fā)揮創(chuàng)造力吧,,玩得開(kāi)心~

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多