Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"cSpell.words": [
"maincontent",
"standfirst",
"tlang",
"youtuber"
]
Expand Down
26 changes: 13 additions & 13 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "build",
"path": "src/plugins/entryPoint",
"group": "build",
"problemMatcher": [],
"label": "npm: build - src/plugins/entryPoint",
"detail": "vite build && cp dist/content_script.js ../../"
}
]
}
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "build",
"path": "src",
"group": "build",
"problemMatcher": [],
"label": "build all modules",
"detail": "pnpm -r run build"
}
]
}
19 changes: 18 additions & 1 deletion src/background/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import {
createAndSetDefaultGroupForCurrentPage,
deleteWord,
favourWord,
generateQuestionAnswers,
getAudioContent,
getCurrentTabId,
getCurrentTabUrl,
getTranslation,
saveTheGuardianArticle,
searchWord,
sendMessageFromBackgroundScriptToContentScript,
setLoginToken,
Expand Down Expand Up @@ -171,13 +173,28 @@ browser.runtime.onMessage.addListener(async (message) => {
deleteWord(message.message);
break;

case "play-audio-from-floating-panel":
case "play-audio-from-floating-panel": {
const t = await getAudioContent(message.message);
sendMessageFromBackgroundScriptToContentScript({
type: "play-audio-from-floating-panel",
message: t,
});
break;
}

case "generate-questions":
console.log("generate-questions");
// const t = await browser.storage.local.get("guardian-article-id");
// console.log(t);
// await generateQuestionAnswers(t["guardian-article-id"]);
break;
case "save-guardian-article":
console.log("Save guardian article...");
await browser.storage.local.set({ "guardian-article-id": "" });
const r = await saveTheGuardianArticle(message.message);
console.log(r);
await browser.storage.local.set({ "guardian-article-id": r._id });
break;
default:
break;
}
Expand Down
2 changes: 1 addition & 1 deletion src/background/background.request.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { baseUrl } from "./constants";
import { getLoginToken } from "./background.utils";

class HttpClient {
constructor(baseURL = baseUrl, timeout = 10000) {
constructor(baseURL = baseUrl, timeout = 3000000) {
// 创建 axios 实例
this.instance = axios.create({
baseURL, // 基础 URL
Expand Down
33 changes: 33 additions & 0 deletions src/background/background.utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,36 @@ export async function getAudioContent(word) {
const response = await client.postBlob("/youdao", { word });
return response;
}

// #region The Guardian
export async function saveTheGuardianArticle(article) {
const group = await createGroup();
const client = new HttpClient();
const { headline, standfirst, content } = article;
const response = await client.post("/article/guardian", {
content,
title: headline,
summary: standfirst,
groupId: group.data._id,
originalUrl: await getCurrentTabUrl(),
});
return response;
}

export async function getGuardianArticle(id) {
const client = new HttpClient();
const response = client.get(`/article/guardian/${id}`);
return response;
}

export async function generateQuestionAnswers(id) {
const client = new HttpClient();
const article = await getGuardianArticle(id);
console.log(article);
const response = await client.post("/deepseek", {
content: article.data.content,
});
console.log(response);
// return response;
}
// #endregion
2 changes: 1 addition & 1 deletion src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Stylish Reader",
"description": "Help you learn English better and easier.",
"developer": { "name": "Toly Feng", "url": "https://stylishreader.com" },
"version": "0.0.25",
"version": "0.0.26",
"icons": {
"48": "icons/stylish-reader-48.png"
},
Expand Down
14 changes: 14 additions & 0 deletions src/plugins/entryPoint/content.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { initializeNYTimes } from "nytimes";
import { initializeBBC } from "../bbcLearningEnglish";
import { initializeGeneralWebSite } from "../general";
import { initializeGuardian } from "../guardian/src/main";
import { initializeTed } from "../ted";
import {
checkUserLoginStatus,
isBBCLearningEnglishWebSite,
isGuardianWebSite,
isNYTimesWebSite,
isTedWebSite,
isYouTubeWebSite,
} from "../utils/utils";
Expand All @@ -28,4 +32,14 @@ checkUserLoginStatus().then(() => {
if (isYouTubeWebSite()) {
initializeYoutube();
}

// 插件 NYTimes
if (isNYTimesWebSite()) {
initializeNYTimes();
}

// 插件 The Guardian
if (isGuardianWebSite()) {
initializeGuardian();
}
});
3 changes: 3 additions & 0 deletions src/plugins/entryPoint/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
"release:copy": "cp ./content/content_script.js ../../",
"preview": "vite preview"
},
"dependencies": {
"nytimes": "file:../nytimes"
},
"devDependencies": {
"npm-run-all": "^4.1.5",
"vite": "^5.2.0"
Expand Down
24 changes: 24 additions & 0 deletions src/plugins/guardian/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
13 changes: 13 additions & 0 deletions src/plugins/guardian/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
16 changes: 16 additions & 0 deletions src/plugins/guardian/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "guardian",
"private": true,
"version": "0.0.0",
"type": "module",
"main": "./src/main.js",
"scripts": {
"dev": "vite",
"build": "vite build",
"release": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^5.4.8"
}
}
130 changes: 130 additions & 0 deletions src/plugins/guardian/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import {
logger,
sendMessageFromContentScriptToBackgroundScript,
} from "../../utils/utils";

let isHeadLineReady = false;
let isStandFirstReady = false;
let isContentReady = false;

export function initializeGuardian() {
console.log("The guardian plugin initialized");
console.log("HeadLine: ", getHeadLine());
console.log("Stand First: ", getStandFirst());
console.log("Content: ", getContent());

console.log("Is ready to read?", isReadyToRead());
saveTheGuardianArticle();
}

function saveTheGuardianArticle() {
const headline = getHeadLine();
const standfirst = getStandFirst();
const content = getContent();
if (isReadyToRead()) {
sendMessageFromContentScriptToBackgroundScript("save-guardian-article", {
headline,
standfirst,
content,
});
} else {
logger("非文章页面");
}
}

function isReadyToRead() {
return isHeadLineReady && isContentReady;
}

function getHeadLineFromHeader() {
const headerNodeList = document.querySelectorAll("header");
// 筛选不符合条件的header,筛选结束后,理论上应该只有一个header了
let headerNodeArray = Array.from(headerNodeList);
headerNodeArray = headerNodeArray.filter((node) => {
return !node.hasAttribute("data-component");
});
// 筛选header的后代节点,筛选中真正的headline,header的后代节点除了headline以外,还有别的元素,例如左侧的旁白
let headerNodeChildrenArray = Array.from(headerNodeArray[0].children);
headerNodeChildrenArray = headerNodeChildrenArray.filter((node) => {
return node.querySelectorAll("figure").length === 0;
});

// 这里经过筛选后,必须只剩下一个孩子元素了,如果剩下多个,或者一个都没有,那么就是出错了
const headerNodeChild = headerNodeChildrenArray[0];

let headerNodeChildChildren = Array.from(headerNodeChild.children);

headerNodeChildChildren = headerNodeChildChildren.filter((child) => {
return child.querySelectorAll("figcaption").length === 0;
});

// 筛选完,应该只剩下一个孩子节点
const headlineNode = headerNodeChildChildren[0];

return headlineNode.innerText;
}

function getHeadLine() {
const nodeList = document.querySelectorAll('[data-gu-name="headline"]');
if (nodeList.length > 1) {
console.log("There are more than one headline");
} else if (nodeList.length < 1) {
console.log("There is no headline");
} else if (nodeList[0].innerText === "") {
const tt = getHeadLineFromHeader();
if (tt) {
isHeadLineReady = true;
return getHeadLineFromHeader();
} else {
return "";
}
} else {
isHeadLineReady = true;
const headerNode = nodeList[0].querySelector("h1");
return headerNode.innerText;
}
}

function getStandFirst() {
const nodeList = document.querySelectorAll('[data-gu-name="standfirst"]');
if (nodeList.length > 1) {
console.log("There are more than one standfirst");
} else if (nodeList.length < 1) {
console.log("There is no standfirst");
} else {
const tl = nodeList[0].querySelectorAll("p");
if (tl.length > 0) {
isStandFirstReady = true;
return Array.from(tl)
.map((p) => p.innerText)
.join("\n");
} else {
isStandFirstReady = false;
return "";
}
}
}

function getContent() {
const nodeList = document.querySelectorAll('[data-gu-name="body"]');
if (nodeList.length > 1) {
console.log("There are more than one body");
} else if (nodeList.length < 1) {
console.log("There is no body");
} else {
const mainContent = nodeList[0].querySelector("#maincontent");
// 仅仅搜索mainContent还不够,里面还会包括广告,newsletter订阅等信息
const pNodeList = mainContent.querySelectorAll("p");
const contentArray = [];
pNodeList.forEach((p) => {
contentArray.push(p.innerText);
});
if (contentArray.length > 0) {
isContentReady = true;
return contentArray;
} else {
isContentReady = false;
return "";
}
}
}
24 changes: 24 additions & 0 deletions src/plugins/nytimes/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
13 changes: 13 additions & 0 deletions src/plugins/nytimes/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
Loading