扩展新增功能:页面嵌入搜索引擎,实时检索发音 (#375)

* 新增README.md页面无跳转即可收听正确读音 的 chromium 扩展

* add 手动安装扩展 方法

* fix no element error

* add comment console log

* change load chrome extension describe

* use prettier format code

* comment console.log

* fix  http protocol audio media no play

* add chromium extension use Reference

* 无页面跳转收听正确读音请安装我们的 chromium 扩展

* 无页面跳转收听正确读音请安装我们的 [chromium 扩展]

* change chromium extension README.md

* add css

* add css extension

* add css extension

* change app.css extension

* 限定权限

* 新增搜索引擎读音检索功能

* 新增功能截图

* 页面嵌入搜索引擎,实时检索发音

* 页面嵌入搜索引擎,实时检索发音

* # 新增功能截图

* change README.md  describe

* change README.md  describe

* format code

* 新增功能截图

* 新增功能截图

* 新增功能截图

* 新增功能截图

* 新增功能截图

* 新增百度汉语搜索和必应辞典搜索

* 默认搜索引擎修改为有道

* add bing search

* add common tool

* until method name change

* fix error and add new search engine

* change chromium url

* 设置默认为新标签页打开搜索

* 完善工具库
yuanchen8911-patch-2
好吧,你想说啥 3 years ago committed by GitHub
parent 9cfdee68f5
commit ec339d9ac9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,33 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
# Matches multiple files with brace expansion notation
# Set default charset
[*.{js,py}]
charset = utf-8
# 4 space indentation
[*.py]
indent_style = space
indent_size = 4
# Tab indentation (no size specified)
[Makefile]
indent_style = tab
# Indentation override for all JS under lib directory
[lib/**.js]
indent_style = space
indent_size = 2
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2

@ -132,12 +132,13 @@
1. 国际音标严式记音纽约音https://github.com/b1f6c1c4/programming-pronunciations-en_US (by @b1f6c1c4)
1. 单词连读 https://corrector.justsong.cn/ (by [@songquanpeng](https://github.com/songquanpeng/pronunciation-corrector))
1. [iOS app](https://apps.apple.com/cn/app/%E7%8C%BF%E5%8D%95%E8%AF%8D-%E4%B8%AD%E5%9B%BD%E7%A8%8B%E5%BA%8F%E5%91%98%E5%AE%B9%E6%98%93%E5%8F%91%E9%9F%B3%E9%94%99%E8%AF%AF%E7%9A%84%E5%8D%95%E8%AF%8D/id1626487291) (by @Chang12)
1. [chromium系浏览器扩展 无页面跳转,实时检索英语发音](https://github.com/jingjingxyk/chinese-programmer-wrong-pronunciation-chromium-extension.git)
### 说明
1. 本着简单的原则, 又为了避免程序猿们出现选择困难症, '正确音标'采用了最接近有道词典音频的英式 DJ 音标, 不代表其唯一性
1. 专业在线英语词典请参考[知乎链接:在线英语词典哪个比较好?](https://www.zhihu.com/question/19707759)
1. 无页面跳转收听正确读音请安装我们的 [chromium 扩展](tools/chromium_extension/README.md)
1. 扩展新增功能:页面嵌入搜索引擎,无页面跳转,实时检索英语发音[chromium 扩展新增功能截图](tools/chromium_extension/images/README.md)
### 参考资料
1. https://www.zhihu.com/question/19739907

@ -1,6 +1,8 @@
# 无页面跳转收听正确读音 的 chromium 扩展
### 手动安装扩展
## [获得最新版扩展](https://github.com/jingjingxyk/chinese-programmer-wrong-pronunciation.git)
## 手动安装扩展
> 1. 下载 [chinese-programmer-wrong-pronunciation](https://github.com/shimohq/chinese-programmer-wrong-pronunciation/archive/refs/heads/master.zip) 然后解压,找到 `tools/chromium_extension` 子目录
> 2. 打开 Chrome输入: `chrome://extensions/`
@ -8,3 +10,16 @@
> 4. 选择 Load unpacked extension... 然后定位到刚才解压的文件夹里面的 `tools/chromium_extension` 目录,确定
> 5. 这就安装好了,去掉 Developer Mode 勾选。
> 6. 打开[`https://github.com/shimohq/chinese-programmer-wrong-pronunciation.git`](https://github.com/shimohq/chinese-programmer-wrong-pronunciation.git)点击单词,即可听正确的单词读音
## 扩展开发参考
1. [content_scripts](https:////developer.chrome.com/docs/extensions/mv3/content_scripts/)
1. [Declare permissions](https:////developer.chrome.com/docs/extensions/mv3/declare_permissions/)
1. [ReplaceGoogleCDN](https://github.com/justjavac/ReplaceGoogleCDN.git)
## note
```text
https://dict.youdao.com/dictvoice?audio=parameter&type=1
```

@ -6,7 +6,26 @@ tr:hover {
color: #fff !important;
background-color: #3ec487 !important;
/*
font-weight: 200;
font-size: 1.1rem;
*/
font-weight: 200;
font-size: 1.1rem;
*/
}
#chinese-programmer-wrong-pronunciation-custom-iframe-box {
border: 8px solid #ddd !important;
border-radius: 8px !important;
box-shadow: 5px 5px 15px #daf5fe !important;
z-index: 999;
position: fixed !important;
}
.chinese-programmer-wrong-pronunciation-custom-iframe-box {
right: 0 !important;
top: 64px !important;
}
#chinese-programmer-wrong-pronunciation-custom-iframe {
width: 100%;
height: 100%;
min-width: 700px !important;
min-height: 600px !important;
}

@ -0,0 +1,8 @@
#!/bin/env bash
set -exu
__DIR__=$(cd "$(dirname "$0")";pwd)
cd ${__DIR__}
npm run format-code

@ -0,0 +1,9 @@
# 新增功能截图
## 嵌入搜索引擎 谷歌搜索
![](https://github.com/jingjingxyk/chinese-programmer-wrong-pronunciation/blob/master/tools/chromium_extension/images/%E6%88%AA%E5%9B%BE2022-06-14-22-11.png?raw=true)
## 嵌入搜索引擎 有道搜索
![](https://raw.githubusercontent.com/jingjingxyk/chinese-programmer-wrong-pronunciation/master/tools/chromium_extension/images/截图2022-06-14-22-10.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

@ -0,0 +1,42 @@
import * as utils from "./utils.js";
import * as components from "./components.js";
import * as searchEngine from "./search-engine.js";
let goToSearchPronounce = (word) => {
let search_engine_name = "gotToGoogleSearch";
// search_engine_name='gotToYouDaoSearch'
// search_engine_name = "goToBingDictSearch";
// search_engine_name = "goToBingSearch";
search_engine_name = "gotToYouDaoSearch";
// search_engine_name = "goToBaiduFanYiSearch";
//let tab = "current_tab";
let tab = "new_tab"; //修改默认为新标签页打开
let opener = components.getSearchEngineOpener();
if (opener && opener.expired_date) {
if (opener.expired_date > new Date().getTime()) {
if (opener.search_engine_name) {
search_engine_name = opener.search_engine_name;
}
if (opener.tab) {
tab = opener.tab;
}
}
}
if (search_engine_name && searchEngine[search_engine_name]) {
console.log(word);
let url = searchEngine[search_engine_name](word);
console.log(url);
if (tab === "new_tab") {
window.open(url, "_blank");
} else {
let iframe = components.getIframe();
iframe.setAttribute("src", url);
}
} else {
console.log("search engine no found !");
}
};
let box = { ...utils, ...components, ...searchEngine, goToSearchPronounce };
export default box;

@ -0,0 +1,131 @@
import { prettyBox } from "./pretty-box.js";
let styleConfig = () => {
let css = document.createElement("link");
css.setAttribute("rel", "stylesheet");
css.setAttribute("type", "text/css");
css.setAttribute("href", chrome.runtime.getURL("css/app.css"));
document.head.appendChild(css);
};
let customElement = () => {
let link = document.createElement("link");
link.setAttribute(
"href",
chrome.runtime.getURL("web-components/x-custom-box.html")
);
document.head.appendChild(link);
};
let getIframe = () => {
let box = document.querySelector(
"#chinese-programmer-wrong-pronunciation-custom-iframe-box"
);
let iframe = null;
if (!box) {
let custom_box = document.createElement(
"x-chinese-programmer-wrong-pronunciation-custom-box"
);
let aside = document.createElement("aside");
aside.setAttribute(
"id",
"chinese-programmer-wrong-pronunciation-custom-iframe-box"
);
aside.setAttribute(
"class",
"chinese-programmer-wrong-pronunciation-custom-iframe-box"
);
aside.setAttribute("draggable", "true");
iframe = document.createElement("iframe");
iframe.setAttribute(
"id",
"chinese-programmer-wrong-pronunciation-custom-iframe"
);
iframe.setAttribute("security", "restricted");
//iframe.setAttribute('sandbox',"")
aside.appendChild(iframe);
custom_box.appendChild(aside);
document.body.appendChild(custom_box);
//设置 box 可 拖拽
prettyBox(aside);
//显示重置按键
//showResetCurrentSearchEngineTab()
} else {
iframe = box.querySelector(
"#chinese-programmer-wrong-pronunciation-custom-iframe"
);
}
return iframe;
};
let opener_key = "how-to-pronounce-from-search-engine-open-tab-opener";
let getSearchEngineOpener = () => {
return JSON.parse(sessionStorage.getItem(opener_key));
};
let showResetCurrentSearchEngineTab = () => {
let div = document.createElement("div");
div.setAttribute(
"id",
"#chinese-programmer-wrong-pronunciation-custom-tools-bar"
);
div.innerHTML = `
<span>关闭搜索页面</span>🥳🥳🥳🥳🥳🥳<span></span>
`;
document
.querySelector("#chinese-programmer-wrong-pronunciation-custom-iframe-box")
.appendChild(div);
};
let setSearchEngineOpener = (search_engine_name, tab) => {
let opener = getSearchEngineOpener();
if (!opener || opener.expired_date < new Date().getTime()) {
search_engine_name = "gotToGoogleSearch";
/*
if (window.confirm('默认有道词典搜索,选择 “取消” 将设置为谷歌搜索,有效期一天')) { //当前页面展示搜索结果
search_engine_name = "gotToYouDaoSearch"
} else {
//新开标签页展示搜索结果
search_engine_name = "gotToGoogleSearch"
}
*/
//页面展示方式,默认有效期一天
let expired_date = new Date().getTime() + 24 * 60 * 60 * 1000;
// expired_date = (new Date()).getTime() + 10000 # test expired
tab = "current_tab";
/*
if (window.confirm('允许当前页面展示搜索结果')) { //当前页面展示搜索结果
tab = "current_tab"
} else {
//新开标签页展示搜索结果
tab = "new_tab"
}
*/
sessionStorage.setItem(
opener_key,
JSON.stringify({
tab: tab,
expired_date: expired_date,
search_engine_name: search_engine_name,
})
);
}
};
let cleanOpener = () => {
sessionStorage.removeItem(opener_key);
};
export {
styleConfig,
customElement,
getIframe,
getSearchEngineOpener,
setSearchEngineOpener,
};

@ -0,0 +1,66 @@
import box from "./box.js";
let init = () => {
let URLObj = new URL(location.href);
console.log(URLObj);
if (document.querySelector("#readme table tbody")) {
box.styleConfig();
box.customElement();
let audio_player = new Audio();
audio_player.setAttribute("autoplay", "true");
document
.querySelector("#readme table tbody")
.addEventListener("click", (event) => {
//console.log(event.target)
// console.log(event.target.nodeType)
// console.log(event.target.nodeName);
let parentElement = event.target.parentElement;
if (parentElement && parentElement.nodeName === "TR") {
if (parentElement.firstElementChild === event.target) {
//使用搜索引擎查询发音
box.goToSearchPronounce(event.target.innerText);
}
}
event.preventDefault();
event.stopPropagation();
let audio_url = null;
if (event.target.nodeName === "TD") {
let aTag = event.target.querySelector("a");
if (aTag) {
audio_url = aTag.getAttribute("href");
}
}
if (event.target.nodeName === "IMG") {
let aTag = event.target.parentNode.parentNode;
audio_url = aTag.getAttribute("href");
}
if (audio_url) {
let desURL = new URL(audio_url);
//console.log(desURL.protocol);
if (desURL.protocol === "http:") {
//skip http
location.href = audio_url;
} else {
// console.log("audio_url:", audio_url);
audio_player.setAttribute("src", audio_url);
}
}
});
document
.querySelector("#readme table tbody")
.addEventListener("mouseover", (event) => {
let parentElement = event.target.parentElement;
if (parentElement && parentElement.nodeName === "TR") {
if (parentElement.firstElementChild === event.target) {
event.target.setAttribute("title", "点击我打开搜索引擎检索");
event.target.style.cursor = "pointer";
}
}
});
} else {
console.log("no found README.md table");
}
};
export { init };

@ -0,0 +1,74 @@
import { addClass, removeClass } from "./utils.js";
let prettyBox = (box) => {
// 参考 https://blog.csdn.net/weixin_41910848/article/details/82218243
let dragging = false;
let diffX = null;
let diffY = null;
box.onmousedown = function (event) {
dragging = true;
let left = box.offsetLeft;
let top = box.offsetTop;
removeClass(
box,
"chinese-programmer-wrong-pronunciation-custom-iframe-box"
);
box.style.left = left + "px";
box.style.top = top + "px";
diffX = event.clientX - left;
diffY = event.clientY - top;
};
document.onmousemove = function (event) {
if (dragging) {
// console.log(event.clientX, event.clientY)
//console.log(diffX, diffY)
let moveX = event.clientX - diffX;
let moveY = event.clientY - diffY;
if (moveX < 0) {
moveX = 0;
} else if (moveX > window.innerWidth - box.offsetWidth) {
moveX = window.innerWidth - box.offsetWidth;
}
if (moveY < 0) {
moveY = 0;
} else if (moveY > window.innerHeight - box.offsetHeight) {
moveY = window.innerHeight - box.offsetHeight;
}
box.style.left = moveX + "px";
box.style.top = moveY + "px";
event.stopPropagation();
event.preventDefault();
}
};
document.onmouseup = function (event) {
dragging = false;
};
box.onmouseup = (event) => {
dragging = false;
};
box.ondragstart = function (event) {
console.log(box.offsetLeft, box.offsetTop);
console.log("开始拖拽");
};
box.ondrag = function () {
console.log(box.offsetLeft, box.offsetTop);
console.log("拖拽中");
};
box.ondragend = function () {
console.log(box.offsetLeft, box.offsetTop);
console.log("拖拽结束");
};
};
export { prettyBox };

@ -0,0 +1,44 @@
let gotToGoogleSearch = (word) => {
word = word.replace(/\s/, "+");
return `https://www.google.com/search?q=how+to+pronounce+${word}`;
};
let gotToYouDaoSearch = (word) => {
word = word.replace(/\s/, "+");
return `https://www.youdao.com/result?word=${word}&lang=en`;
};
let goToBingDictSearch = (word) => {
return `https://cn.bing.com/dict/${word}`;
};
let goToBingSearch = (word) => {
return `https://cn.bing.com/search?q=how%20to%20pronounce%20${word}`;
};
let goToBaiduDictSearch = (word) => {
return `https://dict.baidu.com/s?wd=${word}`;
};
let goToBaiduFanYiSearch = (word) => {
return `https://fanyi.baidu.com/#en/zh/${word}`;
};
let goToBaiDuHanYu = () => {
// 一点飞上天,黄河两头弯;八字大张口,言字中间走;左一扭,右一扭,你一长,我一长,中间加个马大王;心字底,月字旁,一个小勾挂麻糖,坐个车子逛咸阳。
// 56个笔画的字 邉
// U+30EDE (简化版本 U+30EDD
{
"汉".charCodeAt(0).toString(16);
String.fromCharCode("0x6c49");
}
//https://hanyu.baidu.com/s?wd=%E9%82%89
};
export {
goToBaiDuHanYu,
gotToYouDaoSearch,
gotToGoogleSearch,
goToBingDictSearch,
goToBingSearch,
goToBaiduDictSearch,
goToBaiduFanYiSearch,
};

@ -0,0 +1,103 @@
function hasClass(el, className) {
if (el.classList) return el.classList.contains(className);
return !!el.className.match(new RegExp("(\\s|^)" + className + "(\\s|$)"));
}
function addClass(el, className) {
if (el.classList) el.classList.add(className);
else if (!hasClass(el, className)) el.className += " " + className;
}
function removeClass(el, className) {
if (el.classList) el.classList.remove(className);
else if (hasClass(el, className)) {
let reg = new RegExp("(\\s|^)" + className + "(\\s|$)");
el.className = el.className.replace(reg, " ");
}
}
function getCookie(name) {
let arr,
reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
if ((arr = document.cookie.match(reg))) {
return decodeURIComponent(arr[2]);
} else {
return null;
}
//await cookieStore.get({name:name})
}
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
function setCookie(name, value, second, domain) {
var exp = new Date();
exp.setTime(exp.getTime() + second * 1000);
document.cookie =
name +
"=" +
encodeURIComponent(value) +
";expires=" +
exp.toGMTString() +
";path=/;domain=" +
domain +
";SameSite=None;Secure";
}
async function getCookies(domain) {
let cookies = await cookieStore.getAll({ domain: domain });
return cookies;
}
function encodeBase64(str) {
return btoa(encodeURIComponent(str));
}
function decodeBase64(encoded) {
return decodeURIComponent(atob(encoded));
}
function getParameterValue(name) {
let reg = new RegExp("[^?&]?" + encodeURI(name) + "=[^&]+");
let arr = location.search.match(reg);
if (arr != null) {
return decodeURI(arr[0].substring(arr[0].search("=") + 1));
}
return "";
}
function createJSONFile(content, filename) {
let blob = new Blob([JSON.stringify(content)], { type: "application/json" });
let url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.style.display = "none";
a.href = url;
a.download = filename;
a.click();
setTimeout(function () {
window.URL.revokeObjectURL(url);
}, 3000);
}
async function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
async function getMediaDevices() {
return await navigator.mediaDevices.enumerateDevices();
}
// new URLSearchParams
// new URL
// (new Date()).toISOString()
export {
addClass,
removeClass,
hasClass,
setCookie,
getCookie,
encodeBase64,
decodeBase64,
getParameterValue,
sleep,
getMediaDevices,
createJSONFile,
};

@ -1,45 +1,4 @@
{
let URLObj = new URL(location.href);
console.log(URLObj);
if (document.querySelector("#readme table tbody")) {
console.log(chrome.runtime.getURL("css/app.css"));
let css = document.createElement("link");
css.setAttribute("rel", "stylesheet");
css.setAttribute("type", "text/css");
css.setAttribute("href", chrome.runtime.getURL("css/app.css"));
document.head.appendChild(css);
let audio_player = new Audio();
audio_player.setAttribute("autoplay", "true");
document
.querySelector("#readme table tbody")
.addEventListener("click", (event) => {
// console.log(event)
// console.log(event.target.nodeType)
// console.log(event.target.nodeName);
event.preventDefault();
event.stopPropagation();
let audio_url = null;
if (event.target.nodeName === "TD") {
let aTag = event.target.querySelector("a");
if (aTag) {
audio_url = aTag.getAttribute("href");
}
}
if (event.target.nodeName === "IMG") {
let aTag = event.target.parentNode.parentNode;
audio_url = aTag.getAttribute("href");
}
if (audio_url) {
let desURL = new URL(audio_url);
console.log(desURL.protocol);
if (desURL.protocol === "http:") {
//skip http
location.href = audio_url;
} else {
console.log("audio_url:", audio_url);
audio_player.setAttribute("src", audio_url);
}
}
});
}
}
(async () => {
let app = await import(chrome.runtime.getURL("js/app/init.js"));
app.init();
})();

@ -9,7 +9,7 @@
"*://*/shimohq/chinese-programmer-wrong-pronunciation/*",
"*://*/jingjingxyk/chinese-programmer-wrong-pronunciation/*"
],
"run_at": "document_end",
"run_at": "document_idle",
"js": ["js/content-script.js"]
}
],
@ -17,7 +17,16 @@
"declarativeNetRequest",
"declarativeNetRequestWithHostAccess"
],
"host_permissions": ["*://github.com/*"],
"host_permissions": [
"*://github.com/*",
"*://www.google.com/*",
"*://cn.bing.com/*",
"*://www.bing.com/*",
"*://dict.baidu.com/*",
"*://www.youdao.com/*",
"*://dict.youdao.com/*",
"*://fanyi.baidu.com/*"
],
"web_accessible_resources": [
{
"resources": ["*.js", "*.css", "*.html"],

@ -21,6 +21,7 @@
},
{ "header": "x-content-type-options", "operation": "remove" },
{ "header": "x-frame-options", "operation": "remove" },
{ "header": "X-Frame-Options", "operation": "remove" },
{ "header": "permissions-policy", "operation": "remove" },
{ "header": "timing-allow-origin", "operation": "remove" },
{ "header": "cross-origin-embedder-policy", "operation": "remove" },
@ -37,7 +38,18 @@
},
"condition": {
"urlFilter": "*",
"requestDomains": ["github.com", "githubusercontent.com"],
"requestDomains": [
"github.com",
"githubusercontent.com",
"www.google.com",
"cn.bing.com",
"www.bing.com",
"fanyi.baidu.com",
"dict.baidu.com",
"www.youdao.com",
"dict.youdao.com",
"fanyi.baidu.com"
],
"resourceTypes": [
"main_frame",
"sub_frame",

@ -0,0 +1,3 @@
# HTML ImportsHTML Template、Shadow DOM----统称为 Web Components 规范
## Shadow DOM 实现代码隔离

@ -0,0 +1,3 @@
<x-chinese-programmer-wrong-pronunciation-custom-box>
<div>自定义web组件-做代码隔离</div>
</x-chinese-programmer-wrong-pronunciation-custom-box>
Loading…
Cancel
Save