我想让你帮我开发一个 golang 程序,它实现的功能是将一个博客的所有文章爬出来。我会先给你一篇起始文章,页面上会有一个按钮,内容如下,href 指向的就是上一篇文章的内容,例如下面这个例子里,href 的值是:/sarama-producer-hang-another-case/,它对应的文章是:https://xargin.com/sarama-producer-hang-another-case/。 <div> <a href="/sarama-producer-hang-another-case/"> <i></i> Previous Post </a> </div> 我希望这个程序能帮我做的事情就是根据 navigation-item navigation-previous 这个按钮里的信息,一直往前追溯,直到找到所有的文章,此时 href 就是空。这样就能把这个博客的所有文章都能爬下来。 我希望输出一个 md 表格。包含:标题,发表时间,阅读时间,url 链接。 标题和发表时间在这里: <header> <h1>sarama producer hang 又一例</h1> <div> <span class="post-meta-item post-meta-date"> <time>Nov 6, 2022</time> </span> <span class="post-meta-item post-meta-length"> 8 min read </span> </div> </header> post-title 就是标题,datetime 就是发表时间,post-meta-item post-meta-length 就是阅读时间。例如上面这段代码里。标题,发表时间,阅读时间分别是:sarama producer hang 又一例、2022-11-06、8 min。 请将结果输出到一个文件里,就叫 xargin_blos.md。
你好!以下是我为你编写的一个简单的 Go 语言程序,它可以按照你的要求爬取博客文章,并将结果输出到一个名为 "xargin_blogs.md" 的文件中。
goCopy codepackage main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
"time"
"github.com/PuerkitoBio/goquery"
)
const baseURL = "https://xargin.com"
const startURL = "https://xargin.com/sarama-producer-hang-another-case/"
type BlogPost struct {
Title string
PublishDate string
ReadTime string
URL string
}
func main() {
blogPosts := crawlBlogPosts(startURL)
file, err := os.Create("xargin_blogs.md")
if err != nil {
panic(err)
}
defer file.Close()
fmt.Fprintln(file, "| 标题 | 发表时间 | 阅读时间 | URL |")
fmt.Fprintln(file, "| --- | --- | --- | --- |")
for _, post := range blogPosts {
fmt.Fprintf(file, "| %s | %s | %s | %s |\n", post.Title, post.PublishDate, post.ReadTime, post.URL)
}
}
func crawlBlogPosts(url string) []BlogPost {
var posts []BlogPost
for {
post, prevURL, err := getBlogPost(url)
if err != nil {
break
}
posts = append(posts, *post)
if prevURL == "" {
break
}
url = baseURL + prevURL
time.Sleep(1 * time.Second) // 为了避免频繁请求,设置一个简单的延迟
}
return posts
}
func getBlogPost(url string) (*BlogPost, string, error) {
resp, err := http.Get(url)
if err != nil {
return nil, "", err
}
defer resp.Body.Close()
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, "", err
}
title := doc.Find(".post-title").Text()
publishDate, _ := doc.Find(".post-meta-date time").Attr("datetime")
readTime := strings.TrimSpace(doc.Find(".post-meta-item.post-meta-length").Text())
prevURL, _ := doc.Find(".navigation-item.navigation-previous a").Attr("href")
post := &BlogPost{
Title: title,
PublishDate: publishDate,
ReadTime: readTime,
URL: url,
}
return post, prevURL, nil
}
在运行此程序之前,请确保已安装 goquery 库,如果没有安装,可以通过以下命令进行安装:
shCopy codego get github.com/PuerkitoBio/goquery
这个程序会从给定的起始文章链接开始,根据页面上的 "Previous Post" 按钮逐篇向前爬取,直到找不到上一篇文章为止。爬取过程中,程序会提取文章标题、发表时间、阅读时间以及 URL,并将这些信息以 Markdown 表格的形式写入一个名为 "xargin_blogs.md" 的文件。
修改一下实现,md 文件现在只输出三列:文章,发表时间,阅读时间。文章由标题加 url 组合成。例如[中台2023](https://xargin.com/complete-deah-for-middleplatform/),这样更好看一些。 且我想让你在开始爬取文章之前,先在 https://xargin.com 首页上看一下第一篇文章的内容是不是我们已经爬取过了。是否已经爬取过,你可以在 xargin_blogs.md 文件里看第一篇文章的标题。 https://xargin.com 首页的文章可以在 post-title-link 这个 class 里找到。例如第一篇文章,<a href="/complete-deah-for-middleplatform/">中台 2023</a> href 就是地址,“中台 2023” 就是标题。 当你爬取完毕后,请在 md 文档的开头加上: 页面更新时间:xxx(这个获取当前的时间,精确到分钟) 文章总数:xxx(这个数一下总共有多少篇文章就行了) 最后,改一下startURL,它由 https://xargin.com 首页的第一个 post-title-link 决定。
根据你的要求,我对程序进行了修改。现在,它会先检查首页的第一篇文章是否已经爬取过,若已爬取则不再爬取,输出时只包含文章(标题+URL)、发表时间和阅读时间三列。程序会在文件开头添加页面更新时间和文章总数。另外,已将起始链接改为首页的第一篇文章的链接。
goCopy codepackage main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
"time"
"github.com/PuerkitoBio/goquery"
)
const baseURL = "https://xargin.com"
type BlogPost struct {
Title string
PublishDate string
ReadTime string
URL string
}
func main() {
startURL, firstPostTitle := getFirstPostURLAndTitle()
previousPosts, isFirstPostAlreadyCrawled := loadPreviousPosts(firstPostTitle)
if isFirstPostAlreadyCrawled {
fmt.Println("The first post on the homepage has already been crawled.")
return
}
blogPosts := crawlBlogPosts(startURL)
file, err := os.Create("xargin_blogs.md")
if err != nil {
panic(err)
}
defer file.Close()
now := time.Now().Format("2006-01-02 15:04")
totalPosts := len(blogPosts) + len(previousPosts)
fmt.Fprintln(file, fmt.Sprintf("页面更新时间:%s\n文章总数:%d\n", now, totalPosts))
fmt.Fprintln(file, "| 文章 | 发表时间 | 阅读时间 |")
fmt.Fprintln(file, "| --- | --- | --- |")
for _, post := range previousPosts {
fmt.Fprintf(file, "| [%s](%s) | %s | %s |\n", post.Title, post.URL, post.PublishDate, post.ReadTime)
}
for _, post := range blogPosts {
fmt.Fprintf(file, "| [%s](%s) | %s | %s |\n", post.Title, post.URL, post.PublishDate, post.ReadTime)
}
}
func getFirstPostURLAndTitle() (string, string) {
resp, err := http.Get(baseURL)
if err != nil {
panic(err)
}
defer resp.Body.Close()
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
panic(err)
}
postURL, _ := doc.Find(".post-title-link").First().Attr("href")
postTitle := doc.Find(".post-title-link").First().Text()
return baseURL + postURL, postTitle
}
func loadPreviousPosts(firstPostTitle string) ([]BlogPost, bool) {
previousPosts := []BlogPost{}
isFirstPostAlreadyCrawled := false
content, err := ioutil.ReadFile("xargin_blogs.md")
if err != nil {
return previousPosts, isFirstPostAlreadyCrawled
}
lines := strings.Split(string(content), "\n")
for _, line := range lines {
if strings.Contains(line, firstPostTitle) {
isFirstPostAlreadyCrawled = true
}
if strings.HasPrefix(line, "| [") {
parts := strings.Split(line, "|")
postTitleAndURL := strings.TrimSpace(parts[1])
postTitleAndURL = strings.TrimPrefix(postTitleAndURL, "[")
postTitleAndURL = strings.TrimSuffix(postTitleAndURL, ")")
title := strings.Split(postTitleAndURL, "](")[0]
url := strings.Split(postTitleAndURL
```continue
[0]
goCopy code publishDate := strings.TrimSpace(parts[2])
readTime := strings.TrimSpace(parts[3])
post := BlogPost{
Title: title,
PublishDate: publishDate,
ReadTime: readTime,
URL: url,
}
previousPosts = append(previousPosts, post)
}
}
return previousPosts, isFirstPostAlreadyCrawled
}
func crawlBlogPosts(url string) []BlogPost { var posts []BlogPost
goCopy codefor {
post, prevURL, err := getBlogPost(url)
if err != nil {
break
}
posts = append(posts, *post)
if prevURL == "" {
break
}
url = baseURL + prevURL
time.Sleep(1 * time.Second) // 为了避免频繁请求,设置一个简单的延迟
}
return posts
}
func getBlogPost(url string) (*BlogPost, string, error) { resp, err := http.Get(url) if err != nil { return nil, "", err } defer resp.Body.Close()
cssCopy codedoc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, "", err
}
title := doc.Find(".post-title").Text()
publishDate, _ := doc.Find(".post-meta-date time").Attr("datetime")
readTime := strings.TrimSpace(doc.Find(".post-meta-item.post-meta-length").Text())
prevURL, _ := doc.Find(".navigation-item.navigation-previous a").Attr("href")
post := &BlogPost{
Title: title,
PublishDate: publishDate,
ReadTime: readTime,
URL: url,
}
return post, prevURL, nil
}
arduinoCopy code
现在,程序会在爬取文章之前检查首页的第一篇文章是否已经爬取过,若已爬取则程序会退出。程序会在 "xargin_blogs.md" 文件开头添加页面更新时间和文章总数。同时,起始链接已根据首页的第一篇文章的链接进行了更改。
再做一些修改,如果第一篇文章之前已经爬取过了,也请更新一下 md 文件里的更新时间。
好的,我已经修改了程序。现在,即使首页的第一篇文章已经爬取过,程序也会更新 "xargin_blogs.md" 文件里的更新时间。
goCopy codepackage main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
"time"
"github.com/PuerkitoBio/goquery"
)
const baseURL = "https://xargin.com"
type BlogPost struct {
Title string
PublishDate string
ReadTime string
URL string
}
func main() {
startURL, firstPostTitle := getFirstPostURLAndTitle()
previousPosts, isFirstPostAlreadyCrawled := loadPreviousPosts(firstPostTitle)
file, err := os.Create("xargin_blogs.md")
if err != nil {
panic(err)
}
defer file.Close()
now := time.Now().Format("2006-01-02 15:04")
totalPosts := len(previousPosts)
if isFirstPostAlreadyCrawled {
fmt.Println("The first post on the homepage has already been crawled.")
} else {
blogPosts := crawlBlogPosts(startURL)
previousPosts = append(previousPosts, blogPosts...)
totalPosts = len(previousPosts)
}
fmt.Fprintln(file, fmt.Sprintf("页面更新时间:%s\n文章总数:%d\n", now, totalPosts))
fmt.Fprintln(file, "| 文章 | 发表时间 | 阅读时间 |")
fmt.Fprintln(file, "| --- | --- | --- |")
for _, post := range previousPosts {
fmt.Fprintf(file, "| [%s](%s) | %s | %s |\n", post.Title, post.URL, post.PublishDate, post.ReadTime)
}
}
func getFirstPostURLAndTitle() (string, string) {
resp, err := http.Get(baseURL)
if err != nil {
panic(err)
}
defer resp.Body.Close()
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
panic(err)
}
postURL, _ := doc.Find(".post-title-link").First().Attr("href")
postTitle := doc.Find(".post-title-link").First().Text()
return baseURL + postURL, postTitle
}
func loadPreviousPosts(firstPostTitle string) ([]BlogPost, bool) {
previousPosts := []BlogPost{}
isFirstPostAlreadyCrawled := false
content, err := ioutil.ReadFile("xargin_blogs.md")
if err != nil {
return previousPosts, isFirstPostAlreadyCrawled
}
lines := strings.Split(string(content), "\n")
for _, line := range lines {
if strings.Contains(line, firstPostTitle) {
isFirstPostAlreadyCrawled = true
}
if strings.HasPrefix(line, "| [") {
parts := strings.Split(line, "|")
postTitleAndURL := strings.TrimSpace(parts[1])
postTitleAndURL = strings.TrimPrefix(postTitleAndURL, "[")
postTitleAndURL = strings.TrimSuffix(postTitleAndURL, ")")
title := strings.Split(postTitleAndURL, "](")[0]
url := strings.Split(postTitleAndURL, "](")[1]
publishDate := strings.TrimSpace(parts[2])
readTime := strings.TrimSpace(parts[3])
post := BlogPost{
Title: title,
PublishDate: publishDate,
ReadTime: readTime,
URL: url,
}
previousPosts = append(previousPosts, post)
}
}
return previousPosts, isFirstPostAlreadyCrawled
}
非常好。请你再做一点修改,在表格的第一列加上序号,第一行的序号最大。只用告诉我代码有变动的地方
好的,我已经在表格的第一列加上了序号,最新的文章序号最大。这里是变动的代码:
在 main
函数中输出表格时:
goCopy codefmt.Fprintln(file, "| 序号 | 文章 | 发表时间 | 阅读时间 |")
fmt.Fprintln(file, "| --- | --- | --- | --- |")
for index, post := range previousPosts {
fmt.Fprintf(file, "| %d | [%s](%s) | %s | %s |\n", totalPosts-index, post.Title, post.URL, post.PublishDate, post.ReadTime)
}
首先,我在表格的标题行中添加了一个 "序号" 列。接着,在输出每篇文章的循环中,我使用 totalPosts-index
作为序号,这样最新的文章序号将会是最大的。
很好。我现在把这份代码push到 github 上,然后想用 github actions 定时每隔1个小时就执行一次,并把结果也放在当前文件夹,然后 git push 到当前项目。 请帮我写 github actions 代码。并告诉我详细的步骤
要使用 GitHub Actions 定时执行你的 Go 程序并将结果推送到当前项目,可以按照以下步骤操作:
在你的项目根目录下创建一个名为
.github
的文件夹(如果尚不存在),然后在.github
文件夹中创建一个名为workflows
的文件夹。在
workflows
文件夹中创建一个名为crawler.yml
的文件。这个文件将包含 GitHub Actions 的配置。在
crawler.yml
文件中,添加以下配置:
yamlCopy codename: Blog Crawler
on:
schedule:
- cron: '0 * * * *' # 每小时执行一次
jobs:
crawl-and-push:
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.17
- name: Check out repository
uses: actions/checkout@v2
with:
fetch-depth: 0 # 获取完整历史以便正确推送提交
- name: Run crawler
run: go run main.go
- name: Commit and push changes
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
git add xargin_blogs.md
git diff --quiet && git diff --staged --quiet || git commit -m "Update xargin_blogs.md"
git push
这个配置文件的解释:
name
: 定义了 GitHub Actions 的名称。on.schedule
: 使用 cron 语法设置定时触发。这里设置为每小时执行一次。jobs
: 定义了一个名为crawl-and-push
的作业。runs-on
: 指定作业运行在最新的 Ubuntu 环境。steps
: 作业的具体步骤。- 设置 Go 环境。
- 检出项目代码。设置
fetch-depth
为 0 以获取完整的 Git 历史记录。 - 运行爬虫程序。
- 提交并推送更改。首先配置 Git 用户名和电子邮件,然后使用
git add
、git diff
和git commit
添加并提交更改。最后,使用git push
将更改推送到当前项目。
- 将更改提交并推送到 GitHub。GitHub Actions 将在每个小时自动执行你的 Go 程序,将结果更新到
xargin_blogs.md
文件并将更改推送到当前项目。
请注意,要正常运行此 GitHub Actions,你需要将 .github/workflows/crawler.yml
文件提交到你的项目中。当你将这个文件推送到 GitHub 时,GitHub Actions 将开始定时执行你的 Go 程序。
很好。我现在的项目在mac本地,我想在 github 上创建一个项目,请帮我取一个项目名。然后如何把本地项目关联到 githuh 项目,请告诉我步骤
当然可以。首先,我们为你的项目取个名字,比如:xargin-blog-crawler
。接下来,请按照以下步骤将本地项目关联到 GitHub 项目:
在 GitHub 上创建一个新的仓库。登录到你的 GitHub 账户,然后点击右上角的 "+" 图标,选择 "New repository"。在 "Repository name" 输入框中,输入项目名称
xargin-blog-crawler
。你可以选择将仓库设为公开或私有。最后,点击 "Create repository"。在你的本地项目文件夹中,打开终端。如果你还没有初始化 Git 仓库,请运行以下命令:
bashCopy codegit init
- 添加所有文件到 Git 仓库,并提交:
bashCopy codegit add .
git commit -m "Initial commit"
- 将本地 Git 仓库关联到 GitHub 仓库。请将
<your-github-username>
替换为你的 GitHub 用户名:
bashCopy codegit remote add origin https://github.com/<your-github-username>/xargin-blog-crawler.git
- 将本地项目推送到 GitHub 仓库:
bashCopy codegit push -u origin main
如果你的默认分支名为 master
,请使用以下命令:
bashCopy codegit push -u origin master
现在,你的本地项目已关联到 GitHub 项目,并且你的代码已经推送到 GitHub 仓库。你可以在 GitHub 上查看并管理你的项目。
很好。我在填 github 上的Description,请帮我填一下,用中文
当然可以。以下是一个关于 xargin-blog-crawler
项目的中文描述:
xargin-blog-crawler
是一个用 Go 语言编写的博客爬虫程序,用于定期抓取 xargin.com 上的所有文章。程序将文章信息(包括标题、发表时间、阅读时间和 URL)存储在一个 Markdown 文件中,并使用 GitHub Actions 每小时自动更新。
请简短一些,一句话描述。另外,请帮我生成一下 Readme
一句话描述:xargin-blog-crawler
是一个用 Go 编写的博客爬虫,定期抓取并更新 xargin.com 上的文章信息。
关于 README.md,你可以使用以下内容作为起点:
markdownCopy code# xargin-blog-crawler
xargin-blog-crawler 是一个用 Go 编写的博客爬虫,定期抓取并更新 xargin.com 上的文章信息。
## 功能
- 抓取 xargin.com 上的所有文章信息,包括标题、发表时间、阅读时间和 URL
- 将文章信息存储在 Markdown 文件中
- 使用 GitHub Actions 每小时自动更新文章信息
## 使用方法
1. 克隆项目到本地:
git clone https://github.com/<your-github-username>/xargin-blog-crawler.git
markdownCopy code
2. 运行程序:
go run main.go
markdownCopy code
程序将抓取文章信息并将其存储在 `xargin_blogs.md` 文件中。
## GitHub Actions
本项目使用 GitHub Actions 定时执行 Go 程序并将结果推送到当前项目。具体配置请参考 `.github/workflows/crawler.yml` 文件。
请将 <your-github-username>
替换为你的 GitHub 用户名。将这些内容保存到一个名为 README.md
的文件中,并将该文件添加到你的项目中。
我想问下,一般选什么 license
选择合适的许可证取决于你希望他人如何使用和贡献你的项目。以下是一些常见的许可证:
MIT License:MIT 许可证是一个相当宽松的许可证,允许他人自由使用、复制、修改、合并、发布、分发、再许可和/或出售你的代码,唯一的要求是在使用代码的地方包含版权声明和许可声明。这是许多开源项目的首选许可证。
Apache License 2.0:Apache 许可证比 MIT 许可证稍微严格一些,但仍然允许他人自由使用、复制、修改和分发你的代码。此许可证还明确提供了专利授权,并要求在分发时包含许可证副本和任何修改的说明。Apache 许可证适用于希望为使用者提供一定程度的专利保护的项目。
GNU General Public License (GPL):GPL 许可证是一个“传染性”许可证,要求所有基于你的代码的衍生作品都必须使用相同的 GPL 许可证。这意味着,如果他人修改并分发你的代码,他们也必须将源代码开放。这种许可证适用于希望促进开源共享精神的项目。
GNU Lesser General Public License (LGPL):LGPL 许可证类似于 GPL,但它允许将你的代码作为库与其他非 LGPL 项目链接。这使得 LGPL 代码可以在商业软件中使用,但如果他们修改了你的 LGPL 代码,他们仍然需要开放源代码。
BSD License:BSD 许可证与 MIT 许可证相似,允许他人自由使用、复制、修改和分发你的代码。BSD 许可证有多个变体,如 2-Clause 和 3-Clause,其中 3-Clause 要求保留许可证声明、版权声明和免责声明。
总的来说,如果你希望让他人尽可能自由地使用你的代码,那么 MIT、Apache 或 BSD 许可证是不错的选择。如果你希望鼓励开源共享精神并要求衍生作品也开源,则可以选择 GPL 或 LGPL。
更多关于许可证的信息,你可以参考 Choose a License 网站。
现在的程序有点问题,如果第一篇文章已经爬过了,那么现在的 md 文件会被重写,原来的表格也没有了。只有一个更新时间。所以在第一篇文章已经爬过了的情况下,要更新 md 文件里的时间,其他内容不要动
了解。为了解决这个问题,我们需要在更新时间的时候只修改第一行,而保留其他内容。以下是修改后的部分代码:
首先,在 main
函数中,当检测到文章已经爬取过时,我们调用一个新的函数 updateTimestampInFile
来更新时间戳:
goCopy codeif firstArticleExists {
updateTimestampInFile(mdFilename)
return
}
接下来,我们定义新函数 updateTimestampInFile
,用于更新文件中的时间戳:
goCopy codefunc updateTimestampInFile(filename string) {
currentTime := time.Now().Format("2006-01-02 15:04")
fileData, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatalf("Error reading file: %v", err)
}
lines := strings.Split(string(fileData), "\n")
if len(lines) > 0 {
lines[0] = "页面更新时间:" + currentTime
}
updatedFileData := strings.Join(lines, "\n")
err = ioutil.WriteFile(filename, []byte(updatedFileData), 0644)
if err != nil {
log.Fatalf("Error writing file: %v", err)
}
}
这个函数首先读取文件的内容,并将其分割成多行。然后,我们更新第一行的时间戳。最后,将修改后的内容重新组合成字符串,并将其写回文件中。
现在,如果第一篇文章已经被爬取过,程序将只更新文件中的时间戳,而保留其他内容。
main 函数里的这段代码有问题:file, err := os.Create("xargin_blogs.md") if err != nil { panic(err) } defer file.Close() 不应该直接创建,应该先检测是否存在,如果存在就不创建。因为我会多次运行此程序
你是对的。我们应该在写入文件之前检查文件是否已经存在。可以使用 os.OpenFile
函数来打开或创建文件。这是修改后的 main
函数中的相关代码:
goCopy code// 创建或打开文件
file, err := os.OpenFile(mdFilename, os.O_CREATE|os.O_RDWR, 0644)
if err != nil {
panic(err)
}
defer file.Close()
这里,我们使用了 os.O_CREATE
和 os.O_RDWR
标志,这将使 os.OpenFile
函数在文件不存在时创建文件,如果文件已存在,则打开文件以供读写。
现在,当你多次运行此程序时,它将不会覆盖现有的文件,而是打开现有文件以供读写。
非常好。现在github会定期更新这个 md 文件。我想基于这个 md 文件生成一个 html 页面,我想把这个挂到 xargin.com 页面上。 xargin.com 首页有下面几个栏目,我想在最后加一个 archive 栏目。 <ul> <li><a href="http://xargin.com/">Home</a></li> <li><a href="http://xargin.com/readings/">Readings</a></li> <li><a href="http://xargin.com/wechat/">WeChat</a></li> <li><a href="http://github.com/cch123">Github</a></li> <li><a href="http://xargin.com/friends/">Friends</a></li> </ul> 当用户点击 archive 时,展示由 md 文件生成的 html 页面。 但请注意,目录页的最上方的导航栏还是保持网站当前的现状,下方再展示目录。导航栏如下: <header> <div> <div> <div></div> <a href="http://xargin.com"> <span class="logo-text">No Headback</span> </a> <div></div> <nav> <ul> <li><a href="http://xargin.com/">Home</a></li> <li><a href="http://xargin.com/readings/">Readings</a></li> <li><a href="http://xargin.com/wechat/">WeChat</a></li> <li><a href="http://github.com/cch123">Github</a></li> <li><a href="http://xargin.com/friends/">Friends</a></li> </ul> </nav> </div> <div> <div> <div><i></i></div> <div><i></i></div> <div></div> </div> </div> </div> </header> 它包含了几个栏目,例如Github、Friends,和一个暗黑模式的按钮。 我想把这个做成一个插件,用 manifest v3,当用户在浏览 xargin.com 网站时,会自动地加上在导航栏加上 archives 栏目。 请你帮我写代码,并告诉我详细的步骤。
为了实现这个功能,我们需要创建一个Chrome扩展程序。以下是实现此功能的详细步骤:
在你的项目根目录下创建一个名为
chrome-extension
的文件夹。在这个文件夹中,我们将存放扩展程序所需的所有文件。在
chrome-extension
文件夹中创建一个名为manifest.json
的文件。这个文件描述了扩展程序的基本信息和权限。将以下内容添加到该文件:
jsonCopy code{
"manifest_version": 3,
"name": "Xargin Archive",
"version": "1.0",
"description": "在 xargin.com 网站的导航栏中添加一个 archive 栏目",
"permissions": [
"https://xargin.com/*"
],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
},
"content_scripts": [
{
"matches": ["https://xargin.com/*"],
"js": ["content.js"]
}
],
"icons": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
}
- 在
chrome-extension
文件夹中创建一个名为content.js
的文件。这个文件将包含我们用于修改网站内容的JavaScript代码。将以下内容添加到该文件:
javascriptCopy codefunction addArchiveNavItem() {
const navList = document.querySelector('.nav-list');
if (!navList) return;
const archiveListItem = document.createElement('li');
archiveListItem.classList.add('menu-item', 'menu-item-archive');
const archiveLink = document.createElement('a');
archiveLink.classList.add('menu-item-link');
archiveLink.href = 'https://xargin.com/archive.html';
archiveLink.textContent = 'Archive';
archiveListItem.appendChild(archiveLink);
navList.appendChild(archiveListItem);
}
addArchiveNavItem();
这段代码会查找.nav-list
元素,然后创建一个包含Archive链接的新列表项,并将其添加到导航列表中。
(可选)创建一个适当尺寸的图标文件(例如16x16、48x48和128x128像素),并将它们保存到
chrome-extension/images
文件夹中。这些图标将在浏览器的工具栏和扩展程序管理页面中显示。将你的
xargin_blogs.md
文件转换为HTML,并保存为archive.html
。你可以使用在线工具(例如 https://markdowntohtml.com/)或编程库(例如Python的`markdown2`库)将Markdown转换为HTML。将生成的`archive.html`文件上传到你的网站根目录。在Chrome浏览器中,打开扩展程序管理页面(地址栏输入
chrome://extensions
),打开“开发者模式”(右上角的开关),然后点击“加载已解压的扩展程序”按钮。选择你的chrome-extension
文件夹,这将安装并
continue
激活你的扩展程序。现在,当你访问 xargin.com 网站时,导航栏中应该会自动添加一个 Archive 栏目。
将你的扩展程序打包并发布到Chrome Web Store。首先,在扩展程序管理页面(
chrome://extensions
),点击你的扩展程序下方的“打包扩展程序”按钮。这将创建一个.crx
文件和一个.pem
文件。.crx
文件是扩展程序的安装包,.pem
文件是你的私钥,需要妥善保管,以便将来更新扩展程序。访问 Chrome Web Store 开发者控制台(https://chrome.google.com/webstore/devconsole),使用你的Google帐户登录。点击“添加新项目”,然后上传你的`.crx`文件。填写发布扩展程序所需的其他信息(例如详细说明、图标、截图等),然后提交审核。审核通过后,你的扩展程序将在Chrome Web Store上发布,供其他用户下载和安装。
现在,用户可以从 Chrome Web Store 安装你的扩展程序,并在访问 xargin.com 网站时自动看到导航栏中的 Archive 栏目。点击 Archive 栏目将显示archive.html
页面,其中包含从xargin_blogs.md
文件生成的文章列表。
注意:如果你对网站的样式和结构进行了更改,可能需要相应地更新扩展程序中的content.js
文件。在对扩展程序进行更改后,需要重新加载扩展程序并重新打包。如果你已经在 Chrome Web Store 发布了扩展程序,还需要使用你的私钥(.pem
文件)更新扩展程序。
请在 github actions 里面加上将 xargin_blogs.md 转换成 archive.html 的代码。且 archive.html 是放在 github 上的,所以插件需要去读 github 上的 archive.html,它在路径:https://github.com/qcrao/xargin-blog-crawler/archive.html 请据此修改插件代码。 另外,我在执行 github actions 时,报了错误: Error: .github#L1 No event triggers defined in `on`
首先,我们需要将 xargin_blogs.md
转换为 archive.html
。为了实现这一点,你可以使用一个名为 pandoc
的工具。在 GitHub Actions 工作流程中添加以下步骤,以安装 pandoc
并将 xargin_blogs.md
转换为 archive.html
:
yamlCopy code- name: Install pandoc
run: sudo apt-get install pandoc
- name: Convert xargin_blogs.md to archive.html
run: pandoc xargin_blogs.md -o archive.html
现在,将 archive.html
文件添加到 Git 仓库并将其推送到 GitHub:
yamlCopy code- name: Add archive.html to git
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add archive.html
git commit -m "Update archive.html"
git push
这将使得 archive.html
文件可从 GitHub 上访问。但请注意,GitHub 仓库中的文件不能直接作为静态网页访问。因此,你需要将其托管在 GitHub Pages 或其他类似的服务上。假设你已经将该文件托管在 GitHub Pages 上,它的路径将类似于:https://qcrao.github.io/xargin-blog-crawler/archive.html
接下来,我们需要修改插件的代码,以便从新的 URL 读取 archive.html
。在 content.js
文件中,将以下代码:
javascriptCopy codeconst archivePageURL = chrome.runtime.getURL("archive.html");
替换为:
javascriptCopy codeconst archivePageURL = "https://qcrao.github.io/xargin-blog-crawler/archive.html";
关于 GitHub Actions 报错的问题,你需要在 .github/workflows/main.yml
文件中定义至少一个触发器。如果你想让工作流程每小时运行一次,可以添加一个 schedule
触发器,如下所示:
yamlCopy codeon:
schedule:
- cron: '0 * * * *'
这将在每个小时的整点运行 GitHub Actions 工作流程。现在,错误应该已解决。更新你的 GitHub Actions 配置,并验证工作流程是否按预期运行。
我有这个配置: on: schedule: - cron: '0 * * * *' 但我想请你改成当我更新代码时,也能触发工作。 关于插件,能不能直接从 github 上读取 xargin_blogs.md,然后自动转换成 archive.html 文件。
首先,为了在代码更新时触发 GitHub Actions 工作流程,你可以在 .github/workflows/main.yml
文件中添加一个 push
触发器。更新 on
部分如下:
yamlCopy codeon:
push:
branches:
- main
schedule:
- cron: '0 * * * *'
现在,每当你向 main
分支推送代码时,工作流程将自动运行。同时,它仍会在每个小时的整点运行。
关于插件直接从 GitHub 上读取 xargin_blogs.md
文件并将其转换为 HTML,你可以使用一个名为 Showdown 的 JavaScript 库。首先,在 manifest.json
文件中添加对 Showdown 库的引用:
jsonCopy code"content_scripts": [
{
"js": ["showdown.min.js", "content.js"],
...
}
]
请确保你已将 showdown.min.js
文件下载到插件目录中。然后,在 content.js
文件中,将以下代码:
javascriptCopy codeconst archivePageURL = "https://qcrao.github.io/xargin-blog-crawler/archive.html";
替换为:
javascriptCopy codeconst mdURL = "https://raw.githubusercontent.com/qcrao/xargin-blog-crawler/main/xargin_blogs.md";
现在,我们需要获取该 Markdown 文件并使用 Showdown 将其转换为 HTML。更新 fetchAndDisplayArchive()
函数,如下所示:
javascriptCopy codeasync function fetchAndDisplayArchive() {
try {
const mdResponse = await fetch(mdURL);
const mdContent = await mdResponse.text();
const converter = new showdown.Converter();
const archiveHTML = converter.makeHtml(mdContent);
const archiveWindow = window.open("", "_blank");
archiveWindow.document.write(archiveHTML);
archiveWindow.document.close();
} catch (error) {
console.error("Failed to fetch archive:", error);
}
}
这将从 GitHub 上获取 xargin_blogs.md
文件,并使用 Showdown 将其转换为 HTML,然后在新标签页中显示结果。
“请确保你已将 showdown.min.js 文件下载到插件目录中” 这个应该怎么操作
要将 showdown.min.js
文件下载到插件目录中,请按照以下步骤操作:
- 打开 Showdown 的 GitHub 仓库页面:https://github.com/showdownjs/showdown
- 点击 "dist" 文件夹。
- 找到 "showdown.min.js" 文件,点击它。
- 进入 "showdown.min.js" 文件页面后,点击右上角的 "Download" 按钮(形状为一个箭头向下的图标)。
- 将下载的 "showdown.min.js" 文件移动到你的插件目录中,即包含
manifest.json
和content.js
文件的同一文件夹内。
现在,你的插件目录应该包含以下文件:
- manifest.json
- content.js
- showdown.min.js
这样一来,在 manifest.json
中引用的 "showdown.min.js" 文件应该可以正常加载并在 content.js
中使用。
执行 github actions 时,报了错误: Run git config --global user.name "GitHub Actions" [master de288eb] Update xargin_blogs.md 1 file changed, 1 insertion(+), 1 deletion(-) remote: Permission to qcrao/xargin-blog-crawler.git denied to github-actions[bot]. fatal: unable to access 'https://github.com/qcrao/xargin-blog-crawler/': The requested URL returned error: 403 Error: Process completed with exit code 128.
这个错误是因为 GitHub Actions 机器人没有权限将更改推送到你的仓库。为了解决这个问题,你需要为 GitHub Actions 设置一个访问令牌,并在工作流文件中使用它。请按照以下步骤操作:
- 登录到你的 GitHub 账户,然后点击右上角的头像,选择 "Settings"。
- 在左侧导航栏中,找到 "Developer settings",点击进入。
- 选择 "Personal access tokens",然后点击 "Generate new token"。
- 为新的访问令牌添加一个描述,例如 "GitHub Actions",然后勾选 "repo" 选项以赋予仓库的完全访问权限。
- 点击页面底部的 "Generate token" 按钮。生成的令牌将显示在屏幕上,请确保立即复制它,因为你以后将无法再次查看。
- 返回你的 GitHub 仓库,然后转到 "Settings" > "Secrets"。
- 点击 "New repository secret",输入一个名称(例如 "GH_TOKEN"),将你刚刚复制的访问令牌粘贴到 "Value" 字段中,然后点击 "Add secret"。
现在,你已经在仓库中创建了一个名为 "GH_TOKEN" 的密钥。接下来,需要更新 GitHub Actions 工作流文件(.github/workflows/main.yml
)以使用此令牌:
在工作流文件中,找到
git push
行。将该行更改为:
cssCopy codegit push https://${{ secrets.GH_TOKEN }}@github.com/qcrao/xargin-blog-crawler.git HEAD:master
这会将推送操作与你之前创建的访问令牌关联起来。现在,GitHub Actions 应该能够正常推送更改到你的仓库中。
github actions 的权限问题还有存在。报错: ##[debug]git push https://***@github.com/qcrao/xargin-blog-crawler.git HEAD:master ##[debug]' ##[debug]Loading env Run git config --global user.name "GitHub Actions" ##[debug]/usr/bin/bash -e /home/runner/work/_temp/42012cb0-b587-4e4a-8942-89248df67f1c.sh [master d8c38b8] Update xargin_blogs.md 1 file changed, 1 insertion(+), 1 deletion(-) remote: Permission to qcrao/xargin-blog-crawler.git denied to github-actions[bot]. fatal: unable to access 'https://github.com/qcrao/xargin-blog-crawler.git/': The requested URL returned error: 403 Error: Process completed with exit code 128.
抱歉,我在之前的回答中犯了一个错误。在 git push
命令中,你应该使用 :
而不是 /
。请将 GitHub Actions 工作流文件中的 git push
行更改为:
yamlCopy codegit push https://${{ secrets.GH_TOKEN }}@github.com:qcrao/xargin-blog-crawler.git HEAD:master
使用这种格式,GitHub Actions 应该可以正确地推送更改到你的仓库。
还是不对。我知道有个库可以干这个事,你来修改一下吧。 - uses: stefanzweifel/git-auto-commit-action@v4
很好,我来帮你修改 GitHub Actions 工作流文件。请将现有的文件替换为以下内容:
yamlCopy codename: Update Blog Archive
on:
push:
branches:
- master
schedule:
- cron: '0 * * * *'
jobs:
update_blog_archive:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.17
- name: Build and Run Blog Crawler
run: |
go build -o blog_crawler
./blog_crawler
- name: Auto Commit and Push Changes
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "Update xargin_blogs.md"
branch: master
file_pattern: xargin_blogs.md
github_token: ${{ secrets.GITHUB_TOKEN }}
这个工作流文件首先检出你的仓库,然后设置 Go 环境并构建及运行博客爬虫。接下来,它使用 stefanzweifel/git-auto-commit-action@v4 自动提交并推送更改到主分支。请注意,这里使用了内置的 GITHUB_TOKEN
,这样就不需要单独创建一个名为 GH_TOKEN
的仓库密钥。
Set the contents-permission of the default GITHUB_TOKEN to true. (Required to push new commits to the repository) 这里如何操作 Set the contents-permission of the default GITHUB_TOKEN to true
要设置默认 GITHUB_TOKEN
的内容权限,请按照以下步骤操作:
在 GitHub 仓库页面上,导航到 "Settings"(设置)选项卡。
在左侧菜单中,选择 "Actions"(操作)。
向下滚动到 "Actions Permissions"(操作权限)部分。
选择 "Write" 权限选项,这将允许 GitHub Actions 使用默认的
GITHUB_TOKEN
修改仓库内容。点击 "Save"(保存)按钮以保存更改。
现在,GitHub Actions 应该可以使用默认的 GITHUB_TOKEN
将提交推送到仓库。请注意,当您在工作流文件中使用 ${{ secrets.GITHUB_TOKEN }}
时,GitHub 将自动为您提供具有正确权限的令牌。
报错了: INPUT_PUSH_OPTIONS: remote: Permission to qcrao/xargin-blog-crawler.git denied to github-actions[bot]. fatal: unable to access 'https://github.com/qcrao/xargin-blog-crawler/': The requested URL returned error: 403 Error: Invalid status code: 128 at ChildProcess. (/home/runner/work/_actions/stefanzweifel/git-auto-commit-action/v4/index.js:17:19) at ChildProcess.emit (node:events:527:28) at maybeClose (node:internal/child_process:1092:16) at Process.ChildProcess._handle.onexit (node:internal/child_process:302:5) { code: 128 } Error: Invalid status code: 128 at ChildProcess. (/home/runner/work/_actions/stefanzweifel/git-auto-commit-action/v4/index.js:17:19) at ChildProcess.emit (node:events:527:28) at maybeClose (node:internal/child_process:1092:16) at Process.ChildProcess._handle.onexit (node:internal/child_process:302:5)
看起来仍然存在权限问题。在这种情况下,让我们尝试使用您自己的个人访问令牌(PAT)来代替默认的 GITHUB_TOKEN
。请按照以下步骤操作:
在 GitHub 页面上,点击右上角的个人资料图片,然后选择 "Settings"(设置)。
在左侧菜单中,选择 "Developer settings"(开发者设置)。
选择 "Personal access tokens"(个人访问令牌)。
点击 "Generate new token"(生成新令牌)按钮。
为令牌输入描述,例如 "GitHub Actions Commit Token"。
在 "Select scopes"(选择范围)部分,勾选 "repo" 权限。这将允许您的令牌具有完整的仓库访问权限。
向下滚动并点击 "Generate token"(生成令牌)按钮。
将生成的令牌复制到剪贴板。请注意,当您离开此页面时,将无法再次查看令牌。
接下来,将个人访问令牌添加到仓库的 secrets 中:
返回到 GitHub 仓库页面,导航到 "Settings"(设置)选项卡。
在左侧菜单中,选择 "Secrets"(秘密)。
点击 "New repository secret"(新建仓库秘密)按钮。
输入密钥名称,例如 "ACTIONS_PAT",并将您刚刚生成的个人访问令牌粘贴到 "Value"(值)字段中。
点击 "Add secret"(添加秘密)按钮。
现在,您需要更新工作流文件以使用新的个人访问令牌。修改 .github/workflows/main.yml
文件中的 stefanzweifel/git-auto-commit-action
部分,将 GITHUB_TOKEN
替换为您刚刚创建的 ACTIONS_PAT
。
yamlCopy code- name: Commit and push changes
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Update xargin_blogs.md
branch: master
# Replace the line below with the new secret
token: ${{ secrets.ACTIONS_PAT }}
保存更改并推送到仓库。现在,GitHub Actions 应该可以使用您的个人访问令牌将提交推送到仓库。
权限问题搞定了,用了默认的 GITHUB_TOKEN。 现在我需要你修改下页面更新时间,我要你改成用 UTC+8 北京时间,并注明。 现在的时间是这样的,请你修改一下代码: currentTime := time.Now().Format("2006-01-02 15:04") lines := strings.Split(string(fileData), "\n") if len(lines) > 0 { lines[0] = "页面更新时间:" + currentTime }
为了将页面更新时间更改为 UTC+8 北京时间,并注明,请修改如下代码:
goCopy codeimport (
// ...
"time"
)
func main() {
// ...
// 使用 UTC+8 北京时间
loc, _ := time.LoadLocation("Asia/Shanghai")
currentTime := time.Now().In(loc).Format("2006-01-02 15:04")
lines := strings.Split(string(fileData), "\n")
if len(lines) > 0 {
lines[0] = "页面更新时间(北京时间):" + currentTime
}
// ...
}
这段代码将首先加载 "Asia/Shanghai" 时区,然后获取当前时间并将其转换为北京时间。接下来,它会将更新时间插入到 xargin_blogs.md
文件的第一行,并注明是北京时间。
之前我让你帮我开发的插件,请你给取一个名字
你可以给这个插件取名为:“XarginBlogArchive”,这个名字简洁明了,同时包含了 Xargin 博客和归档(Archive)的关键信息。
content.js 代码有点乱了,请重新发一遍完整的。 请注意,你应该先把 md 文件下载下来,然后使用 showdown.min.js 来转换成 html。并且请每隔一小时重新下载 md 文件然后转换成 html。
以下是完整的 content.js
代码:
javascriptCopy code(function () {
const archiveTab = `
<li class="menu-item menu-item-archive">
<a class="menu-item-link" href="javascript:void(0)" id="archive-link">Archive</a>
</li>
`;
const navList = document.querySelector('.nav-list');
navList.insertAdjacentHTML('beforeend', archiveTab);
const archiveLink = document.getElementById('archive-link');
const loadMDFile = async () => {
const response = await fetch('https://raw.githubusercontent.com/qcrao/xargin-blog-crawler/main/xargin_blogs.md');
const mdText = await response.text();
return mdText;
};
const convertMDToHTML = (mdText) => {
const converter = new showdown.Converter();
const html = converter.makeHtml(mdText);
return html;
};
const createArchiveContent = (htmlContent) => {
const archiveContainer = document.createElement('div');
archiveContainer.style.display = 'none';
archiveContainer.id = 'archive-content';
archiveContainer.innerHTML = htmlContent;
return archiveContainer;
};
const showArchive = () => {
const mainContent = document.querySelector('.site-main');
mainContent.style.display = 'none';
const archiveContent = document.querySelector('#archive-content');
archiveContent.style.display = 'block';
};
const hideArchive = () => {
const mainContent = document.querySelector('.site-main');
mainContent.style.display = 'block';
const archiveContent = document.querySelector('#archive-content');
archiveContent.style.display = 'none';
};
let isArchiveVisible = false;
let isContentLoaded = false;
archiveLink.addEventListener('click', async () => {
if (!isContentLoaded) {
const mdText = await loadMDFile();
const htmlContent = convertMDToHTML(mdText);
const archiveContent = createArchiveContent(htmlContent);
document.body.appendChild(archiveContent);
isContentLoaded = true;
}
if (!isArchiveVisible) {
showArchive();
isArchiveVisible = true;
} else {
hideArchive();
isArchiveVisible = false;
}
});
setInterval(async () => {
const mdText = await loadMDFile();
const htmlContent = convertMDToHTML(mdText);
const archiveContent = document.querySelector('#archive-content');
if (archiveContent) {
archiveContent.innerHTML = htmlContent;
}
}, 3600000);
})();
在这个版本的代码中,loadMDFile
函数会从 GitHub 下载 xargin_blogs.md
文件,然后使用 convertMDToHTML
函数将 Markdown 转换为 HTML。每隔一小时,setInterval
函数会重新下载 MD 文件并转换为 HTML。
最后,能不能写个简单的 html 页面,我点击它之后,简单弹出一个页面,上面写上: If you don't keep moving, you'll quickly fall behind. 请给这个一个酷炫的效果。 另外,我需要改 manifest 文件吗
你可以创建一个简单的 HTML 页面,如下所示:
htmlCopy code<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Motivational Quote</title>
<style>
body {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
margin: 0;
background-color: #282c34;
font-family: Arial, sans-serif;
}
h1 {
color: #61dafb;
font-size: 2.5rem;
text-align: center;
animation: fadeIn 3s ease-in-out;
}
@keyframes fadeIn {
0% {
opacity: 0;
transform: translateY(100px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
</style>
</head>
<body>
<h1>If you don't keep moving, you'll quickly fall behind.</h1>
<script>
document.addEventListener('click', () => {
alert("If you don't keep moving, you'll quickly fall behind.");
});
</script>
</body>
</html>
在这个示例中,我添加了一个淡入动画效果,并将文字颜色更改为蓝色。当用户点击页面时,将弹出一个包含引用的警告框。
对于之前的插件,你不需要修改 manifest
文件。只要确保 manifest
文件中已经包含了 content.js
文件的引用即可。
这个效果很不错。不过我想把页面放大一点,例如宽度是原来的2倍。你告诉我改哪个地方
要将页面宽度扩大到原来的2倍,您只需在<style>
标签内添加一些CSS代码。首先,在body
样式中,将min-height
更改为100%
,然后添加一个新的container
类,如下所示:
htmlCopy code<style>
body {
display: flex;
align-items: center;
justify-content: center;
min-height: 100%;
margin: 0;
background-color: #282c34;
font-family: Arial, sans-serif;
}
.container {
width: 200%;
height: 100%;
}
h1 {
color: #61dafb;
font-size: 2.5rem;
text-align: center;
animation: fadeIn 3s ease-in-out;
}
@keyframes fadeIn {
0% {
opacity: 0;
transform: translateY(100px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
</style>
接下来,在<body>
标签内添加一个<div>
元素,并将其类名设置为container
:
htmlCopy code<body>
<div class="container">
<h1>If you don't keep moving, you'll quickly fall behind.</h1>
</div>
<script>
document.addEventListener('click', () => {
alert("If you don't keep moving, you'll quickly fall behind.");
});
</script>
</body>
现在,页面宽度将扩大到原来的2倍。
content.js 代码执行起来有问题, fetch('https://raw.githubusercontent.com/qcrao/xargin-blog-crawler/main/xargin_blogs.md'); 这个 url 没有返回内容。 实际上直接访问这个地址就能得到内容:https://github.com/qcrao/xargin-blog-crawler/blob/master/xargin_blogs.md 我改成这个 url 后,访问出错了,报:CORS error 请修改一下 content.js 代码
因为GitHub会阻止跨域请求,所以直接获取 https://github.com/qcrao/xargin-blog-crawler/blob/master/xargin_blogs.md 内容会遇到CORS错误。解决此问题的方法是使用一个代理服务器来获取文件内容,这样就可以避免CORS限制。有一个名为CORS Anywhere
的简单服务可以实现这个功能。
请将content.js
文件中的fetch请求替换为以下代码:
javascriptCopy codeconst proxyUrl = 'https://cors-anywhere.herokuapp.com/';
const targetUrl = 'https://raw.githubusercontent.com/qcrao/xargin-blog-crawler/main/xargin_blogs.md';
fetch(proxyUrl + targetUrl)
.then((response) => response.text())
.then((mdText) => {
//...原来的代码
});
这将通过CORS Anywhere代理服务器获取MD文件的内容,从而避免CORS错误。
注意:CORS Anywhere服务仅用于开发目的,不建议将其用于生产环境。在生产环境中使用时,请考虑自己部署一个类似的CORS代理服务器,或者寻找其他解决方案。
GitHub会阻止跨域请求,为什么就不能访问? 有没有其他方式实现。
GitHub 阻止跨域请求是因为它在响应头部设置了 CORS (Cross-Origin Resource Sharing) 策略,这是一种浏览器安全机制。当发起跨域请求时,浏览器会检查响应头的 CORS 策略。如果策略不允许当前站点访问资源,浏览器就会抛出 CORS 错误。
另一种解决方案是将 md 文件托管在支持 CORS 的服务器上,或者使用服务器端脚本获取文件内容。这里有一个简单的解决方案:将 xargin_blogs.md 文件托管在一个支持 CORS 的服务器上,例如 Netlify。
- 首先,访问 https://app.netlify.com/ 并使用 GitHub 账号登录。
- 点击“New site from Git”,选择 GitHub 作为 Git 提供商。
- 在“Authorize Netlify”页面,授权 Netlify 访问你的 GitHub 账户。
- 选择你的 xargin-blog-crawler 仓库,然后点击“Deploy site”。
- 等待部署完成。部署完成后,Netlify 会生成一个网址,例如
https://your-site-name.netlify.app
。 - 访问
https://your-site-name.netlify.app/xargin_blogs.md
,这个 URL 就是你需要的 md 文件。
将 content.js
中的 fetch
请求替换为以下代码:
javascriptCopy codeconst targetUrl = 'https://your-site-name.netlify.app/xargin_blogs.md';
fetch(targetUrl)
.then((response) => response.text())
.then((mdText) => {
//...原来的代码
});
这样一来,你就可以避免 CORS 错误,因为 Netlify 默认允许所有跨域请求。
注意:请将 your-site-name
替换为你实际的 Netlify 站点名称。
需要填: Basic build settings If you’re using a static site generator or build tool, we’ll need these settings to build your site. 有 base directory,build command,publish directory。应该怎么填
在这种情况下,由于你只是托管一个静态的 md 文件,而不是构建一个完整的网站,你不需要填写“Basic build settings”。只需让这些字段为空,然后继续部署。Netlify 将直接将你的仓库部署为静态站点,而无需运行任何构建命令。
Base directory
- 保持空白。Build command
- 保持空白。Publish directory
- 保持空白。
完成这些设置后,点击“Deploy site”按钮。Netlify 将使用默认设置部署你的仓库。
loadMDFile 完整的代码给我看一下 Netlify 部署完了。 targetUrl 是这样的,const targetUrl = 'https://644bf1c8a89dff009d00df4b--verdant-marigold-d5e883.netlify.app/xargin_blogs.md'; 请你修改一下原有的代码: const loadMDFile = async () => { // const response = await fetch('https://raw.githubusercontent.com/qcrao/xargin-blog-crawler/main/xargin_blogs.md'); const response = await fetch('https://github.com/qcrao/xargin-blog-crawler/blob/master/xargin_blogs.md'); const mdText = await response.text(); return mdText; }; 请避免 CQRS 错误
首先,将 targetUrl
更新为你在 Netlify 部署的 URL。这将避免 CORS 错误,因为你不再从 GitHub 仓库的原始内容中获取数据。在你的 loadMDFile
函数中,将 fetch
URL 更改为你在 Netlify 上的 URL:
javascriptCopy codeconst targetUrl = 'https://644bf1c8a89dff009d00df4b--verdant-marigold-d5e883.netlify.app/xargin_blogs.md';
const loadMDFile = async () => {
const response = await fetch(targetUrl);
const mdText = await response.text();
return mdText;
};
现在,你的插件应该能够正常工作,从你在 Netlify 上部署的仓库中加载 MD 文件,而不会遇到 CORS 错误。每次更新 GitHub 仓库时,Netlify 都会自动更新你的部署,这意味着插件将获取最新的数据。
还是报了 CQRS
抱歉,我之前误导了你。使用 Netlify 部署并不能解决 CORS 问题。CORS 错误是浏览器安全策略的一部分,以防止未经授权的跨域请求。要解决这个问题,我们需要设置一个代理服务器,以避免直接从客户端发起跨域请求。
我建议使用一个名为 "CORS Anywhere" 的代理服务器。这是一个简单的开源项目,允许你在任何跨域请求前添加一个代理服务器 URL。
以下是如何修改 loadMDFile
函数以使用 CORS Anywhere 代理服务器:
javascriptCopy codeconst targetUrl = 'https://644bf1c8a89dff009d00df4b--verdant-marigold-d5e883.netlify.app/xargin_blogs.md';
const corsProxyUrl = 'https://cors-anywhere.herokuapp.com/';
const loadMDFile = async () => {
const response = await fetch(corsProxyUrl + targetUrl);
const mdText = await response.text();
return mdText;
};
这段代码将使用 CORS Anywhere 代理服务器,从而解决 CORS 错误。
需要注意的是,CORS Anywhere 允许任何人使用它的免费服务,但由于资源限制,它可能无法满足大量请求的需求。在生产环境中,你可能需要自行搭建一个 CORS 代理服务器,或使用其他可靠的代理服务。
不想用 CORS Anywhere,有其他方案吗
既然你不想使用 CORS Anywhere,我们可以尝试另一种方法:将网站部署到同一个域名下,这样就不会有跨域请求的问题。
你可以使用 GitHub Pages 或者 Netlify(你已经用过了)来部署你的网站和 MD 文件。将你的网站和 MD 文件部署到同一个域名下,就可以避免 CORS 问题。
假设你的网站已经部署在了 https://yourwebsite.com
,那么你应该将 MD 文件部署到类似 https://yourwebsite.com/xargin_blogs.md
的路径下。这样,你的插件就可以直接从这个地址加载 MD 文件,而不会遇到 CORS 错误。
这是修改后的 loadMDFile
函数:
javascriptCopy codeconst targetUrl = 'https://yourwebsite.com/xargin_blogs.md';
const loadMDFile = async () => {
const response = await fetch(targetUrl);
const mdText = await response.text();
return mdText;
};
请将 yourwebsite.com
替换为你实际使用的域名,并确保你已将 MD 文件部署到正确的路径。这样一来,你的插件就可以正常工作了,而不会遇到 CORS 错误。
还有其他方案吗。这个插件我是给其他人做的,所以不太可能部署到他人的服务器上
既然你不希望将 MD 文件部署到其他人的服务器上,另一个解决方案是创建一个简单的代理服务器,用于转发请求并处理 CORS 问题。
你可以使用云函数服务,如 AWS Lambda 或者 Vercel,创建一个简单的代理服务器。以下是一个使用 Vercel 的示例:
- 安装 Vercel CLI:
Copy codenpm install -g vercel
- 创建一个名为
proxy-server
的新文件夹,并在其中创建一个index.js
文件,内容如下:
javascriptCopy codemodule.exports = async (req, res) => {
const targetUrl = 'https://raw.githubusercontent.com/qcrao/xargin-blog-crawler/main/xargin_blogs.md';
try {
const response = await fetch(targetUrl);
const mdText = await response.text();
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Content-Type', 'text/plain');
res.status(200).send(mdText);
} catch (error) {
res.status(500).send('An error occurred while fetching the MD file.');
}
};
在
proxy-server
文件夹中运行vercel
命令来部署这个云函数。Vercel 会给你一个 URL,类似
https://your-proxy-server.vercel.app
。修改插件中的
loadMDFile
函数,将targetUrl
替换为你的 Vercel 代理服务器 URL:
javascriptCopy codeconst targetUrl = 'https://your-proxy-server.vercel.app';
const loadMDFile = async () => {
const response = await fetch(targetUrl);
const mdText = await response.text();
return mdText;
};
现在,当插件请求代理服务器时,代理服务器会将请求转发到 MD 文件的实际地址。由于代理服务器已经处理了 CORS 问题,插件将能够正常加载 MD 文件。
我看它的请求头是: Request URL: https://644bf1c8a89dff009d00df4b--verdant-marigold-d5e883.netlify.app/xargin_blogs.md Request Method: GET Status Code: 200 Referrer Policy: no-referrer-when-downgrade 但我看另外一个成功的请求,这种应该也算是 CQPS: Request URL: https://avatars.githubusercontent.com/u/90444738?v=4?v=3&s=88 Request Method: GET Status Code: 200 Remote Address: 185.199.110.133:443 Referrer Policy: strict-origin-when-cross-origin 是不是只有修改一下 Referrer Policy 就可以成功请求。
CORS(跨域资源共享)问题和 Referrer Policy 是两个不同的概念。Referrer Policy 控制着浏览器在发送请求时,是否包含请求来源页面的 URL 信息。而 CORS 是一种安全机制,用于控制浏览器能否访问跨域资源。
在这个问题上,Referrer Policy 并不会导致 CORS 错误。CORS 错误是因为服务器没有返回适当的 CORS 头部,以允许浏览器访问请求的资源。
在你的示例中,GitHub 的 URL(https://avatars.githubusercontent.com)已经设置了适当的 CORS 头部,因此浏览器可以正常访问这个资源。然而,Netlify 部署的 MD 文件没有设置允许跨域访问的 CORS 头部,所以会出现 CORS 错误。
要解决这个问题,你需要在 Netlify 服务器上设置 CORS 头部。以下是如何在 Netlify 配置跨域访问:
在你的项目根目录创建一个名为
_headers
的文件。在
_headers
文件中,添加以下内容:
mathematicaCopy code/*
Access-Control-Allow-Origin: *
- 提交并推送更改到你的代码库。
现在,Netlify 服务器会返回允许跨域访问的 CORS 头部,浏览器应该能够正常加载 MD 文件。请注意,这样做会允许任何网站访问你的 MD 文件。如果你希望限制访问,请在 Access-Control-Allow-Origin
头部设置一个特定的来源。
这个我要看响应头的哪个字段,才能判断支不支持跨域访问
要确定服务器是否支持跨域访问,你需要查看响应头中的 Access-Control-Allow-Origin
字段。
如果服务器支持跨域访问,响应头中的 Access-Control-Allow-Origin
字段值应为允许的域名,或者为 *
表示允许任何域名访问。
例如:
- 允许特定域名跨域访问:
arduinoCopy codeAccess-Control-Allow-Origin: https://example.com
- 允许所有域名跨域访问:
makefileCopy codeAccess-Control-Allow-Origin: *
请注意,Access-Control-Allow-Origin
只是 CORS 头部的一部分。根据你的需求,你可能还需要设置其他 CORS 相关头部,如 Access-Control-Allow-Methods
(允许哪些 HTTP 方法)和 Access-Control-Allow-Headers
(允许哪些 HTTP 头部)。
很好,跨域问题解决了。但是页面是空的。请你看一下如何调试一下,可以加一些调试日志
要在 content.js 中添加调试日志,你可以使用 console.log()
函数输出一些关键信息。这样,当你在浏览器的开发者工具中查看 Console 时,你可以看到这些调试信息。请参考以下示例代码来在关键步骤中添加调试日志:
javascriptCopy codeconst loadMDFile = async () => {
const targetUrl = 'https://your-url-here/xargin_blogs.md';
console.log('Fetching MD file:', targetUrl);
const response = await fetch(targetUrl);
if (response.ok) {
console.log('MD file fetched successfully');
const mdText = await response.text();
return mdText;
} else {
console.log('Error fetching MD file:', response.status, response.statusText);
return '';
}
};
// 其他函数保持不变...
document.addEventListener('DOMContentLoaded', async () => {
console.log('Extension loaded');
const mdText = await loadMDFile();
if (mdText) {
console.log('MD text:', mdText);
const htmlContent = convertMarkdownToHTML(mdText);
console.log('HTML content:', htmlContent);
injectArchiveSection(htmlContent);
} else {
console.log('Failed to load MD file');
}
});
现在,当你加载插件并访问 xargin.com 时,浏览器的开发者工具中的 Console 会显示调试日志。这将帮助你找到可能存在的问题。如果你发现某些步骤没有按预期执行,你可以在 Console 中查看详细信息以进行进一步调试。
打印了:MD file fetched successfully。 我还看到其他错误: vTools failed to load source map: Could not load content for chrome-extension://bcadekaiikofbodhjkijlmccaeebhnbd/showdown.min.js.map: System error: net::ERR_BLOCKED_BY_CLIENT gi
这个错误信息表示浏览器尝试加载 showdown.min.js 的源映射文件(source map),但由于某种原因(如拦截器或浏览器设置)而被阻止。源映射文件主要用于调试目的,它可以帮助开发者在源代码中更容易地找到问题。然而,在大多数情况下,缺少源映射文件并不会影响插件的正常运行。
由于这个错误不太可能是导致页面为空的原因,你可以继续查看 Console 中的其他日志。请检查以下方面:
- 确保已经正确获取了 Markdown 文本。你可以检查
console.log('MD text:', mdText);
打印出的内容。 - 确保
convertMarkdownToHTML(mdText)
函数成功将 Markdown 转换为 HTML。你可以检查console.log('HTML content:', htmlContent);
打印出的内容。 - 确保
injectArchiveSection(htmlContent)
函数成功地将生成的 HTML 内容插入到页面中。
如果你发现任何步骤中的问题,请进一步调查并修复。你也可以在这里询问更多问题,以便我们为你提供帮助。
const loadMDFile = async () => { // const targetUrl = 'https://644bf1c8a89dff009d00df4b--verdant-marigold-d5e883.netlify.app/xargin_blogs.md'; const targetUrl = 'https://master--verdant-marigold-d5e883.netlify.app/xargin_blogs.md'; const response = await fetch(targetUrl); if (response.ok) { console.log('MD file fetched successfully'); const mdText = await response.text(); console.log('MD text:', mdText); return mdText; } else { console.log('Error fetching MD file:', response.status, response.statusText); return ''; } }; 我这样加了日志,打印了:MD file fetched successfully 但是没打印出来:MD text
看起来 response.text()
这一步可能没有正常执行。这可能是因为 response.text()
是异步操作,但是我们没有等待它完成。在这种情况下,我们需要确保在返回 mdText
之前等待 response.text()
完成。为了解决这个问题,请尝试将 console.log('MD text:', mdText);
放在 await response.text();
这一行之后,如下所示:
javascriptCopy codeconst loadMDFile = async () => {
// const targetUrl = 'https://644bf1c8a89dff009d00df4b--verdant-marigold-d5e883.netlify.app/xargin_blogs.md';
const targetUrl = 'https://master--verdant-marigold-d5e883.netlify.app/xargin_blogs.md';
const response = await fetch(targetUrl);
if (response.ok) {
console.log('MD file fetched successfully');
const mdText = await response.text();
console.log('MD text:', mdText);
return mdText;
} else {
console.log('Error fetching MD file:', response.status, response.statusText);
return '';
}
};
这样,你应该能够在控制台看到打印出的 Markdown 文本。
已经转换成了 html,但是像是没有成功插入页面中,页面上是 html 源代码
看起来可能是在将转换后的 HTML 插入页面时出了问题。请检查 updatePageContent
函数中是否正确地将转换后的 HTML 插入页面。这是一个可能的实现:
javascriptCopy codeconst updatePageContent = (html) => {
const contentElement = document.getElementById('content');
if (contentElement) {
contentElement.innerHTML = html;
} else {
console.error('Could not find the content element to update');
}
};
这个函数会查找具有 content
ID 的元素并将其 innerHTML
属性设置为传入的 HTML 字符串。如果找不到该元素,它会在控制台中打印一条错误消息。
请确保你的 HTML 页面中有一个具有 content
ID 的元素。例如:
htmlCopy code<div id="content"></div>
如果问题仍然存在,请提供一些关于如何插入 HTML 的更多详细信息,以便我们能够提供更具体的建议。
我看了下其他页面的内容都是放在 class="site-content" 子class="content-area" 这个下面,要不你也试试。当前 content.js 里这一块的代码是: const archiveContent = createArchiveContent(htmlContent); document.body.appendChild(archiveContent); const createArchiveContent = (htmlContent) => { const archiveContainer = document.createElement('div'); archiveContainer.style.display = 'none'; archiveContainer.id = 'archive-content'; archiveContainer.innerHTML = htmlContent; return archiveContainer; };
根据您提供的信息,我们需要在页面上找到具有 site-content
类和 content-area
子类的元素,并将生成的 HTML 内容插入到其中。以下是修改后的 createArchiveContent
和 updatePageContent
函数:
javascriptCopy codeconst createArchiveContent = (htmlContent) => {
const archiveContainer = document.createElement('div');
archiveContainer.style.display = 'none';
archiveContainer.id = 'archive-content';
archiveContainer.innerHTML = htmlContent;
return archiveContainer;
};
const updatePageContent = (html) => {
const siteContentElement = document.querySelector('.site-content');
const contentAreaElement = siteContentElement.querySelector('.content-area');
if (contentAreaElement) {
const archiveContent = createArchiveContent(html);
contentAreaElement.appendChild(archiveContent);
} else {
console.error('Could not find the content-area element to update');
}
};
首先,updatePageContent
函数会查找具有 site-content
类的元素,然后查找其子元素中具有 content-area
类的元素。如果找到了 content-area
元素,它将创建一个 archive-content
元素并将其附加到 content-area
元素。
在 main
函数中,您应该调用 updatePageContent
函数,而不是直接将 archiveContent
附加到 document.body
:
javascriptCopy codeasync function main() {
const mdText = await loadMDFile();
const htmlContent = convertMDToHTML(mdText);
updatePageContent(htmlContent);
}
main();
这应该将生成的 HTML 内容插入到具有 content-area
类的元素中。如果仍然存在问题,请提供更多详细信息,以便我们提供更具体的建议。
createArchiveContent 函数在这里调用: archiveLink.addEventListener('click', async () => { if (!isContentLoaded) { const mdText = await loadMDFile(); const htmlContent = convertMDToHTML(mdText); console.log('HTML content:', htmlContent); const archiveContent = createArchiveContent(htmlContent); document.body.appendChild(archiveContent); isContentLoaded = true; } if (!isArchiveVisible) { showArchive(); isArchiveVisible = true; } else { hideArchive(); isArchiveVisible = false; } }); updatePageContent 要放在哪里调用,现在你给我的 content.js 代码里面并没有 updatePageContent
抱歉给您带来的困扰。请将 createArchiveContent
和 updatePageContent
函数替换为以下代码,并将 updatePageContent
函数调用放在事件监听器中。这里是修改后的代码:
javascriptCopy codeconst createArchiveContent = (htmlContent) => {
const archiveContainer = document.createElement('div');
archiveContainer.style.display = 'none';
archiveContainer.id = 'archive-content';
archiveContainer.innerHTML = htmlContent;
return archiveContainer;
};
const updatePageContent = (archiveContent) => {
const siteContentElement = document.querySelector('.site-content');
const contentAreaElement = siteContentElement.querySelector('.content-area');
if (contentAreaElement) {
contentAreaElement.appendChild(archiveContent);
} else {
console.error('Could not find the content-area element to update');
}
};
archiveLink.addEventListener('click', async () => {
if (!isContentLoaded) {
const mdText = await loadMDFile();
const htmlContent = convertMDToHTML(mdText);
console.log('HTML content:', htmlContent);
const archiveContent = createArchiveContent(htmlContent);
updatePageContent(archiveContent);
isContentLoaded = true;
}
if (!isArchiveVisible) {
showArchive();
isArchiveVisible = true;
} else {
hideArchive();
isArchiveVisible = false;
}
});
现在,当您单击 archiveLink
时,将调用 updatePageContent
函数,并将 archiveContent
传递给它。这将将生成的 HTML 内容插入到具有 content-area
类的元素中。
如果仍然存在问题,请提供更多详细信息,以便我们提供更具体的建议。
问题好像出在 html 转换上,我把转出来的 html copy 到一个文件里,在浏览器里打开后并不能渲染出表格,只有一堆文字
问题可能是由于使用 Showdown 转换 Markdown 时的设置导致的。让我们检查并更新 Showdown 的设置,以确保正确渲染 HTML 表格。请将 convertMDToHTML
函数替换为以下代码:
javascriptCopy codeconst convertMDToHTML = (mdText) => {
const converter = new showdown.Converter({
tables: true,
simplifiedAutoLink: true,
strikethrough: true,
tasklists: true,
});
const htmlContent = converter.makeHtml(mdText);
return htmlContent;
};
这里,我们在创建 Showdown 转换器时启用了一些选项,包括 tables
,以确保正确渲染表格。现在,当您使用这个新的 convertMDToHTML
函数时,它应该会正确渲染 HTML 表格。
请尝试使用这个更新的函数,并让我们知道是否解决了问题。
现在看起来不错了,基本的表格出来了,但是不美观,请美化一下效果。另外,在 archive 页面时,点击 archive 时会跳回到其他页面,请改一下这种行为,在 archive 页面点击时,刷新一下就行了。请据此修改代码。
首先,我们来美化表格。您可以在 content.js 的头部添加以下 CSS 样式。这将应用一些基本的样式以提高表格的外观:
javascriptCopy codeconst style = document.createElement('style');
style.textContent = `
#archive-content table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
#archive-content th,
#archive-content td {
border: 1px solid #ccc;
padding: 8px;
text-align: left;
}
#archive-content th {
background-color: #f2f2f2;
font-weight: bold;
}
#archive-content tr:nth-child(even) {
background-color: #f2f2f2;
}
`;
document.head.appendChild(style);
接下来,为了解决在 archive 页面点击时的问题,请修改 archiveLink
的事件监听器,将它替换为以下代码:
javascriptCopy codearchiveLink.addEventListener('click', async (event) => {
if (window.location.pathname.includes('archive')) {
event.preventDefault();
window.location.reload();
} else {
if (!isContentLoaded) {
const mdText = await loadMDFile();
const htmlContent = convertMDToHTML(mdText);
console.log('HTML content:', htmlContent);
const archiveContent = createArchiveContent(htmlContent);
document.body.appendChild(archiveContent);
isContentLoaded = true;
}
if (!isArchiveVisible) {
showArchive();
isArchiveVisible = true;
} else {
hideArchive();
isArchiveVisible = false;
}
}
});
这里,我们检查当前页面的路径是否包含 'archive'。如果是这样,我们阻止默认的链接行为,并刷新页面。如果不是,我们继续按照原来的逻辑执行。这将在点击 archive 链接时刷新 archive 页面,而不是跳回到其他页面。
css 效果有了,但是还不好。 请再次修改 css 代码,使得页面宽度不要占据整个页面,宽度占页面一半,且居中。 表格不要把实际的边框画出来,两行相邻的表格用不同的颜色区分一下就行。 关于配色,我看它的页面上: 暗黑模式下: .dark-mode body { color: var(--dark-mode-primary-text-color); background-color: var(--dark-mode-bg-color); } 正常模式下就是白色。 最后,当鼠标经过文章标题时,请将字体颜色改成蓝色,并且鼠标并成手形。
根据您的要求,我对 CSS 代码进行了修改。以下是更新后的样式:
javascriptCopy codeconst style = document.createElement('style');
style.textContent = `
#archive-content {
width: 50%;
margin: 0 auto;
}
#archive-content table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
#archive-content th,
#archive-content td {
padding: 8px;
text-align: left;
}
#archive-content th {
background-color: #f2f2f2;
font-weight: bold;
}
#archive-content tr:nth-child(even) {
background-color: #f2f2f2;
}
#archive-content tr:nth-child(odd) {
background-color: #fff;
}
#archive-content a {
color: inherit;
text-decoration: none;
}
#archive-content a:hover {
color: blue;
cursor: pointer;
}
`;
document.head.appendChild(style);
这段代码将使表格宽度占据页面的一半,并居中显示。同时,表格的边框已被移除,相邻行使用不同的颜色进行区分。当鼠标悬停在文章标题上时,字体颜色会变为蓝色,鼠标指针会变成手形。
您可以将此段代码替换到原有的 CSS 代码中。
很好。 现在请在 site-content 居中展示文字“历史文章”。当鼠标经过文章标题时,请把字体也变粗。最后一个问题时,当网站开启暗黑模式时,字体展示效果很差,请做相应修改。 这个网站的页面上有一个暗黑模式的按钮,但是我不知道它是如何生效的,请告诉我方法找到生效方法。
首先,根据您的要求修改 CSS 代码,使得 "历史文章" 文字居中显示,并在鼠标悬停时加粗:
javascriptCopy codeconst style = document.createElement('style');
style.textContent = `
...
#archive-content h2 {
text-align: center;
}
#archive-content a:hover {
color: blue;
cursor: pointer;
font-weight: bold;
}
`;
document.head.appendChild(style);
接下来,关于暗黑模式生效的问题。您可以通过以下步骤找到生效方法:
- 打开网站,确保网站处于暗黑模式。
- 右键点击暗黑模式切换按钮,选择 "检查" 选项,这将打开浏览器的开发者工具。
- 在 "Elements" 标签页中,您将看到切换按钮的 HTML 代码。通常,按钮会有一个
id
或class
属性,使得 JavaScript 可以轻松地找到并添加事件监听器。 - 在 "Sources" 或 "Debugger" 标签页中查找与该按钮相关的 JavaScript 代码。您可以在代码中搜索按钮的
id
或class
,找到相关的事件监听器。 - 仔细阅读事件监听器的代码,找到暗黑模式生效的逻辑。这可能涉及为 HTML 元素添加或删除 CSS 类,或修改 CSS 变量的值。
对于暗黑模式下的字体显示问题,请告诉我具体的问题,以便我为您提供解决方案。
现在请在 site-content 居中展示文字“历史文章”。历史文章我需要你添加到 class="site-content" 这里
好的,我明白您的需求。要将 "历史文章" 文字添加到 class="site-content"
中并居中显示,请修改 createArchiveContent
函数,如下所示:
javascriptCopy codeconst createArchiveContent = (htmlContent) => {
const siteContent = document.querySelector('.site-content');
const archiveContainer = document.createElement('div');
archiveContainer.style.display = 'none';
archiveContainer.id = 'archive-content';
archiveContainer.innerHTML = `<h2>历史文章</h2>${htmlContent}`;
siteContent.appendChild(archiveContainer);
return archiveContainer;
};
这段代码会找到页面中的 class="site-content"
元素,并在其中创建一个新的 div
元素,该元素包含 "历史文章" 文字和您提供的 HTML 内容。然后将新创建的 div
元素添加到 siteContent
中。此外,已经在之前的 CSS 代码中设置了使 "历史文章" 文字居中显示。
请将这段代码替换到您现有的 content.js
文件中的 createArchiveContent
函数。
再把“历史文章”的字体改成: font-size: 30px; font-weight: 800; letter-spacing: -.01em; 另外,我想把“历史文章”和下面的内容间距多一些,应该怎么改?
要实现您的需求,请在 createArchiveContent
函数中添加内联样式。以下是修改后的 createArchiveContent
函数:
javascriptCopy codeconst createArchiveContent = (htmlContent) => {
const siteContent = document.querySelector('.site-content');
const archiveContainer = document.createElement('div');
archiveContainer.style.display = 'none';
archiveContainer.id = 'archive-content';
const title = '<h2 style="font-size: 30px; font-weight: 800; letter-spacing: -.01em; margin-bottom: 20px;">历史文章</h2>';
archiveContainer.innerHTML = `${title}${htmlContent}`;
siteContent.appendChild(archiveContainer);
return archiveContainer;
};
在这段代码中,我为 "历史文章" 文字添加了内联样式以更改字体大小、字体粗细和字母间距。同时,我还增加了一个 margin-bottom
属性,将其值设置为 20px
以增加标题与下面内容之间的间距。您可以根据需要调整间距值。
请将这段代码替换到您现有的 content.js
文件中的 createArchiveContent
函数。
关于暗黑模式下,字体应该变成白色。否则看不清。
为了让字体在暗黑模式下变为白色,您可以将以下 CSS 代码添加到 createArchiveContent
函数中:
cssCopy code<style>
.dark-mode #archive-content {
color: white;
}
</style>
以下是修改后的 createArchiveContent
函数,其中包含了暗黑模式下白色字体的 CSS 代码:
javascriptCopy codeconst createArchiveContent = (htmlContent) => {
const siteContent = document.querySelector('.site-content');
const archiveContainer = document.createElement('div');
archiveContainer.style.display = 'none';
archiveContainer.id = 'archive-content';
const title = '<h2 style="font-size: 30px; font-weight: 800; letter-spacing: -.01em; margin-bottom: 20px;">历史文章</h2>';
const darkModeStyle = `
<style>
.dark-mode #archive-content {
color: white;
}
</style>
`;
archiveContainer.innerHTML = `${darkModeStyle}${title}${htmlContent}`;
siteContent.appendChild(archiveContainer);
return archiveContainer;
};
现在,在暗黑模式下,归档内容的字体颜色将变为白色。请将这段代码替换到您现有的 content.js
文件中的 createArchiveContent
函数。
表格的颜色是不是也得跟着变一下,否则字看不清了。另外,我想问下暗黑模式的原理是什么,为什么按下按钮就能变暗黑呢?
对于表格颜色,您可以根据暗黑模式进行调整。您可以添加一些 CSS 代码,以便在暗黑模式下改变表格行的背景颜色。例如:
cssCopy code<style>
.dark-mode #archive-content tr:nth-child(even) {
background-color: #2b2b2b;
}
.dark-mode #archive-content tr:nth-child(odd) {
background-color: #383838;
}
</style>
您可以将此 CSS 代码添加到之前提供的 createArchiveContent
函数中的 darkModeStyle
变量中。这将使表格的行在暗黑模式下具有不同的颜色。
关于暗黑模式的原理,通常,网站会使用 JavaScript 监听一个按钮的点击事件,当按钮被点击时,会在网页的某个元素(通常是 <body>
或 <html>
元素)上添加或移除一个表示暗黑模式的 CSS 类名(例如 dark-mode
)。同时,CSS 代码中会为这个类名定义一套不同的样式规则,这些规则将覆盖默认的颜色、背景颜色等。当页面元素具有这个类名时,它们将应用这些新的样式规则,从而呈现出暗黑模式的外观。
在您提到的网站中,这个原理也是一样的。它使用了一个按钮来切换暗黑模式,并在点击按钮时为 <body>
元素添加或移除 dark-mode
类名。然后,CSS 代码中定义了一套 dark-mode
类名的样式规则,这些规则会覆盖默认的颜色和背景颜色等。
我用 inspect 看表格的 css 是: .dark-mode #archive-content { color: white; } 所以暗黑模式下,表格还是白色的,而字体也是白色的,所以看不清字
了解了。要解决这个问题,您可以为暗黑模式下的表格行定义不同的背景颜色。这样,文字就能在不同的背景颜色上清晰可见。可以使用以下 CSS 代码:
cssCopy code<style>
.dark-mode #archive-content tr:nth-child(even) {
background-color: #2b2b2b;
}
.dark-mode #archive-content tr:nth-child(odd) {
background-color: #383838;
}
</style>
将此 CSS 代码添加到之前提供的 createArchiveContent
函数中的 darkModeStyle
变量中。这将使表格的行在暗黑模式下具有不同的颜色,从而使白色文本在暗色背景上清晰可见。
很好。还有点小问题,暗黑模式下表格的标题行颜色还是白色的,这个要变一下。另外,鼠标经过标题时的颜色也要变一下
我明白了。要解决这个问题,您可以按照以下步骤操作:
- 修改暗黑模式下的表格标题行颜色:
cssCopy code<style>
.dark-mode #archive-content th {
background-color: #1a1a1a;
}
</style>
将此 CSS 代码添加到之前提供的 createArchiveContent
函数中的 darkModeStyle
变量中。这将使表格标题行在暗黑模式下具有不同的颜色。
- 修改鼠标经过标题时的颜色:
cssCopy code<style>
#archive-content tr:hover {
background-color: #555;
}
.dark-mode #archive-content tr:hover {
background-color: #666;
}
</style>
将此 CSS 代码添加到之前提供的 createArchiveContent
函数中的 style
和 darkModeStyle
变量中。这将使鼠标悬停在表格行上时,背景颜色发生变化。这些颜色可以根据您的喜好进行自定义。
正常模式下鼠标经过表格某一行的时候,背景色太深了,需要改一下。
了解。要修改正常模式下鼠标经过表格行时的背景颜色,您可以将之前提供的 CSS 代码稍作修改:
cssCopy code<style>
#archive-content tr:hover {
background-color: #f0f0f0;
}
</style>
将此 CSS 代码添加到之前提供的 createArchiveContent
函数中的 style
变量中。这将改变正常模式下鼠标经过表格行时的背景颜色。您可以根据您的喜好调整 #f0f0f0
为其他颜色。
这个网站在暗黑模式下页面的背景色是 #282c35,你能再把表格的颜色和鼠标经过时的颜色修改一下,让他更 match 一些
当然可以。为了让表格和暗黑模式下的背景色更协调,请修改 createArchiveContent
函数中的 style
变量,如下所示:
javascriptCopy codeconst style = `
<style>
#archive-content table {
width: 50%;
margin: 0 auto;
border-collapse: collapse;
}
#archive-content th, #archive-content td {
padding: 12px;
text-align: left;
}
#archive-content tr:nth-child(even) {
background-color: #343a46;
}
#archive-content tr:hover {
background-color: #434a56;
}
.dark-mode #archive-content tr:nth-child(even) {
background-color: #383e4b;
}
.dark-mode #archive-content tr:hover {
background-color: #484f5c;
}
#archive-content a {
text-decoration: none;
color: inherit;
}
#archive-content a:hover {
color: blue;
font-weight: bold;
}
.dark-mode #archive-content a:hover {
color: #5fa1ff;
}
</style>
`;
现在,表格的颜色和鼠标经过时的颜色应该与暗黑模式下的背景色更协调。如有需要,您可以根据喜好继续调整颜色值。
非常好,我现在想把表格和上面的文字之间的间距调大一点,请告诉我改哪里的代码。
要增加表格和上面文字之间的间距,您可以在 createArchiveContent
函数中的 style
变量里添加一个 margin-top
属性给表格。例如,将间距设置为 20px:
javascriptCopy codeconst style = `
<style>
#archive-content table {
width: 50%;
margin: 20px auto; /* 这里添加了 20px 的上外边距 */
border-collapse: collapse;
}
/* 其他样式保持不变 */
</style>
`;
现在表格和上面的文字之间的间距应该增大了。您可以根据需要调整间距值。
我加载插件的时候,会报了一个 warning: Permission 'https://xargin.com/*' is unknown or URL pattern is malformed. 在这一行: "permissions": [ "https://xargin.com/*" ],
这个警告是因为您在插件的manifest.json
文件中的permissions
字段里使用了一个不完整的URL。您应该在URL末尾添加一个路径,例如:
jsonCopy code"permissions": [
"https://xargin.com/*/*"
],
这将允许您的插件访问https://xargin.com/
下的所有子路径。如果您的插件只需要访问特定路径,您可以将通配符(*)替换为特定的路径。例如,如果您的插件只需要访问https://xargin.com/some/path
,则可以使用:
jsonCopy code"permissions": [
"https://xargin.com/some/path"
],
然后重新加载插件,警告应该消失了。
你这个 permissions 写得不对吧。我看了另一个插件,是这么写的: "permissions": [ "scripting", "activeTab" ], "content_scripts": [ { "matches": ["*://chat.openai.com/*"], "js": ["addCheckboxes.js", "bulkDeleteConversations.js"] } ]
抱歉,我理解错了您的问题。在这种情况下,您不需要将https://xargin.com/*
添加到permissions
字段中,因为您已经通过content_scripts
指定了您的插件需要访问的特定URL模式。您可以将permissions
字段修改为如下形式:
jsonCopy code"permissions": [
"scripting",
"activeTab"
],
然后,确保您在content_scripts
部分中指定了正确的URL模式匹配。例如:
jsonCopy code"content_scripts": [
{
"matches": ["https://xargin.com/*"],
"js": ["your_content_script.js"]
}
]
这样,您的插件将仅在与https://xargin.com/*
匹配的网页上运行。不会再出现之前的警告。
还有一个问题,点击插件图标,弹出来的页面太窄了,请优化一下。另外,我想在底部增加一个 copyright,html 里的代码如下: <div> <p></p> </div> js 代码如下: // Update copyright year const currentYear = new Date().getFullYear(); document.getElementById('copyright').innerHTML = '© ' + currentYear + ' <a href="https://github.com/qcrao" target="_blank">@qcrao</a>'; 请告诉我应该怎么改动
要调整插件图标弹出页面的宽度,您需要修改插件弹出页面的HTML文件中的CSS。以下是一个调整后的示例:
- 在插件弹出页面的HTML文件的
<head>
部分,添加一个<style>
标签:
htmlCopy code<!DOCTYPE html>
<html>
<head>
<style>
body {
width: 300px; /* 或者您喜欢的任何宽度 */
}
.footer {
margin-top: 20px;
text-align: center;
}
</style>
</head>
<body>
<!-- 页面内容 -->
<div class="footer">
<p id="copyright"></p>
</div>
<script src="popup.js"></script>
</body>
</html>
将
width
属性值更改为您喜欢的宽度,例如300px
。这将使弹出页面的宽度增加。添加
.footer
类的CSS样式,以便在版权信息和页面其他部分之间添加一些间距,并将其居中对齐。
关于您提供的JavaScript代码,它看起来已经正确设置了版权信息。只要将它放在popup.js
文件中,它应该按预期工作。
copyright css 再修改一下。字体改成白色,字体调大一点,另外,copyright 应该排在页面下方,现在在右面右方
要调整版权信息的样式,请根据以下建议修改<style>
标签中的CSS代码:
htmlCopy code<!DOCTYPE html>
<html>
<head>
<style>
body {
width: 300px; /* 或者您喜欢的任何宽度 */
display: flex;
flex-direction: column;
min-height: 100vh;
}
.footer {
margin-top: auto;
padding: 15px 0;
background-color: #282c35;
text-align: center;
color: white;
font-size: 14px;
}
</style>
</head>
<body>
<!-- 页面内容 -->
<div class="footer">
<p id="copyright"></p>
</div>
<script src="popup.js"></script>
</body>
</html>
这里的变更包括:
为
body
添加display: flex
和flex-direction: column
,使其成为一个flex容器,并确保所有子元素沿着垂直轴排列。为
body
添加min-height: 100vh
,以确保它至少占据整个视口高度。将
.footer
的margin-top
更改为auto
,这将使其始终放在页面底部。为
.footer
添加padding
,background-color
,color
和font-size
属性以设置字体颜色、大小和背景色。
这些更改将使版权信息始终出现在页面底部,并调整其样式以更易于阅读。
现在又有点问题了,@qcrao 现在是红色,请给我改成白色。 If you don't keep moving, you'll quickly fall behind. 现在这句话超出了页面,请修改。
要将版权信息中的@qcrao
文本颜色更改为白色,并修复页面宽度,请按照以下建议修改HTML和CSS代码:
htmlCopy code<!DOCTYPE html>
<html>
<head>
<style>
body {
width: 300px; /* 或者您喜欢的任何宽度 */
display: flex;
flex-direction: column;
min-height: 100vh;
overflow-wrap: break-word; /* 用于处理长文本换行 */
}
.footer {
margin-top: auto;
padding: 15px 0;
background-color: #282c35;
text-align: center;
color: white;
font-size: 14px;
}
.footer a {
color: white;
text-decoration: none;
}
</style>
</head>
<body>
<!-- 页面内容 -->
<div class="footer">
<p id="copyright"></p>
</div>
<script src="popup.js"></script>
</body>
</html>
这里的变更包括:
为
body
添加overflow-wrap: break-word
属性,以确保长文本换行,避免超出页面。添加
.footer a
选择器,为链接设置颜色和装饰效果。这将使@qcrao
链接文本变为白色。
这些更改应解决您提到的问题。
没有解决长文本的问题。是不是因为文字是在 container 里面?另外,我想给 @qcrao 加一个下划线。请修改代码
如果长文本仍然超出页面,请检查您的代码以确保已应用相应的CSS属性。按照以下代码修改HTML和CSS以解决这个问题,并为@qcrao
添加下划线:
htmlCopy code<!DOCTYPE html>
<html>
<head>
<style>
body {
width: 300px; /* 或者您喜欢的任何宽度 */
display: flex;
flex-direction: column;
min-height: 100vh;
}
.container {
overflow-wrap: break-word; /* 用于处理长文本换行 */
padding: 0 10px; /* 为容器添加一些左右内边距 */
}
.footer {
margin-top: auto;
padding: 15px 0;
background-color: #282c35;
text-align: center;
color: white;
font-size: 14px;
}
.footer a {
color: white;
text-decoration: none;
}
.footer a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<!-- 页面内容 -->
</div>
<div class="footer">
<p id="copyright"></p>
</div>
<script src="popup.js"></script>
</body>
</html>
这里的变更包括:
添加一个
.container
类,并为其添加overflow-wrap: break-word
属性。这将确保长文本换行,避免超出页面。另外,添加了左右内边距。为
.footer a:hover
添加选择器,以便在鼠标悬停在@qcrao
链接上时显示下划线。
使用这些更改应该解决长文本的问题,并为@qcrao
添加下划线。
还是没有解决。长文本在 html 页面里如下: <div> <h1>If you don't keep moving, you'll quickly fall behind.</h1> </div>
抱歉,我理解错了您的需求。为了确保长标题不会超出页面边界,我们可以使用CSS的word-break
属性。请按照以下代码修改CSS:
cssCopy codebody {
width: 300px; /* 或者您喜欢的任何宽度 */
display: flex;
flex-direction: column;
min-height: 100vh;
}
.container {
padding: 0 10px; /* 为容器添加一些左右内边距 */
}
.container h1 {
word-break: break-word; /* 用于处理长标题换行 */
font-size: 16px; /* 可以根据需要调整字体大小 */
}
.footer {
margin-top: auto;
padding: 15px 0;
background-color: #282c35;
text-align: center;
color: white;
font-size: 14px;
}
.footer a {
color: white;
text-decoration: none;
}
.footer a:hover {
text-decoration: underline;
}
这里的变更包括:
- 添加一个
.container h1
选择器,并为其添加word-break: break-word
属性。这将确保长标题换行,避免超出页面。您也可以根据需要调整字体大小。
使用这些更改应该解决长标题的问题。
还是没有解决,请看一下现在的 body 代码: <div> <h1>If you don't keep moving, you'll quickly fall behind.</h1> </div> <div> <p></p> </div>
抱歉给您带来困扰。请尝试将以下 CSS 代码添加到您的样式表中:
cssCopy codebody {
width: 300px; /* 或者您喜欢的任何宽度 */
display: flex;
flex-direction: column;
min-height: 100vh;
overflow-wrap: break-word;
}
这将确保长文本在 body 元素内换行,避免超出页面。同时,将其他相关样式保持不变。这样应该可以解决长文本问题。
还是不行。我有个想法,请将 If you don't keep moving, you'll quickly fall behind. 这句话分成 2 行吧,应该就够了
当然可以,为了将标题分成两行,您可以在 HTML 代码中添加一个 <br>
标签来实现换行。请将您的 <h1>
标签修改如下:
htmlCopy code<h1>If you don't keep moving, <br> you'll quickly fall behind.</h1>
这将把标题分成两行,解决了超出页面的问题。
请解释一下这段代码的作用是什么: 另外,当我点击插件图标时,它就会在这段代码的地方弹出错误: Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-FnL6sZSaZxovkAWFaHORSgpJ+tOxwjn3EBwHT5dSy38='), or a nonce ('nonce-...') is required to enable inline execution. Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' 'wasm-unsafe-eval' 'inline-speculation-rules' http://localhost:* http://127.0.0.1:*". Either the 'unsafe-inline' keyword, a hash ('sha256-FnL6sZSaZxovkAWFaHORSgpJ+tOxwjn3EBwHT5dSy38='), or a nonce ('nonce-...') is required to enable inline execution. 请修改代码。
这段代码添加了一个事件监听器,当用户在文档中点击时,它会弹出一个警告框,显示指定的文本。在您的例子中,文本为 "If you don't keep moving, <br>you'll quickly fall behind."。
关于错误提示,它是由于您使用了内联 JavaScript 代码,而插件的 Content Security Policy(CSP) 限制了内联脚本的执行。要解决这个问题,您可以将这段内联脚本移到单独的 JavaScript 文件中(例如,popup.js
)。
- 删除
<script>
标签及其内容:
htmlCopy code<script>
document.addEventListener('click', () => {
alert("If you don't keep moving, <br>you'll quickly fall behind.");
});
</script>
- 将事件监听器的代码移到
popup.js
文件中:
javascriptCopy codedocument.addEventListener('click', () => {
alert("If you don't keep moving, <br>you'll quickly fall behind.");
});
通过将内联脚本移动到单独的 JavaScript 文件中,您应该能够避免 CSP 的限制。
script 里的代码和这里的代码是不是重复了: <div> <h1>If you don't keep moving, <br />you'll quickly fall behind.</h1> </div>
是的,这段内联脚本中的文本与 <h1>
标签中的文本相同。但是,它们的功能不同。<h1>
标签在页面上直接显示文本,而内联脚本中的代码在用户点击页面时弹出一个警告框,显示文本。如果您希望在点击页面时弹出的警告框显示与 <h1>
标签中相同的文本,那么它们之间的文本应该是一致的。如果您不希望在点击时弹出警告框,可以删除内联脚本的相关代码。
我去掉了这段代码,效果和没去掉是一样的。所以之前应该是没有弹出警告框。
了解。如果在删除内联脚本代码之前没有触发警告框,那么很可能是因为 Content Security Policy(内容安全策略)限制了内联脚本的执行。在这种情况下,删除内联脚本不会影响页面的表现,因为它已经被阻止执行。您可以根据需要调整页面上的其他元素和样式,以达到期望的效果。
我把它单独放在了 popup.js 里面也没有出现警告框。另外,这两句话间的间距能不能设置的多一点。
如果您将代码移至 popup.js
中,并且仍然没有弹出警告框,您可能需要检查代码是否正确,以及 popup.js
是否正确链接到 HTML 页面。请确保在 popup.html
中的 <script>
标签正确引用了 popup.js
文件,如下所示:
htmlCopy code<script src="popup.js"></script>
关于两句话之间的间距问题,您可以通过设置 <br>
标签的样式来调整它们。例如,在 popup.css
文件中添加以下 CSS 规则,以增加两行之间的间距:
cssCopy codebr {
line-height: 1.5em;
}
您可以根据需要调整 line-height
的值,以达到期望的间距效果。
很好。现在请帮我在页面顶部加上 Xargin Blog Archive,并在下面加一条分隔线
要在页面顶部添加 "Xargin Blog Archive" 标题以及一条分隔线,请按照以下步骤操作:
- 在
popup.html
中的<body>
标签内,在<div class="container">
之前添加以下 HTML 代码:
htmlCopy code<header>
<h2>Xargin Blog Archive</h2>
<hr>
</header>
- 现在,在
popup.css
文件中添加以下 CSS 规则,以对标题和分隔线进行样式设置:
cssCopy codeheader {
text-align: center;
padding-bottom: 15px;
}
header h2 {
margin-bottom: 10px;
}
hr {
width: 80%;
margin: 0 auto;
border: 0;
height: 1px;
background-color: #ccc;
}
这将使得标题居中,并在标题下方添加一条分隔线。您可以根据需要调整 CSS 规则,以达到期望的样式效果。
现在我准备把这个插件 push 到 github。请帮我写一个项目说明和 readme。项目说明简短一点。 readme 里包括插件的作用,安装和使用方法,原理。原理部分要提到 netlify
项目说明: Xargin Blog Archive Extension 是一个轻量级的浏览器插件,用于查看 Xargin 博客的文章归档。它提供了一种简便的方式来查看过去的博客文章列表,并支持暗黑模式。
README.md:
Xargin Blog Archive Extension
Xargin Blog Archive Extension 是一个轻量级的浏览器插件,用于查看 Xargin 博客的文章归档。它提供了一种简便的方式来查看过去的博客文章列表,并支持暗黑模式。
功能
- 查看 Xargin 博客的文章归档
- 支持暗黑模式
- 点击文章标题以访问相应文章
安装
- 克隆或下载此 GitHub 仓库到本地。
- 打开浏览器的扩展程序管理页面。
- 启用“开发者模式”。
- 点击“加载已解压的扩展程序”,选择本地仓库的文件夹。
使用方法
- 安装插件后,点击浏览器工具栏上的插件图标。
- 在弹出的页面中,浏览文章归档。
- 点击文章标题以访问相应文章。
原理
插件通过 Fetch API 从 Xargin 博客的 Netlify 部署中获取 Markdown 文档。Markdown 文档包含所有文章的归档列表。插件使用 Showdown 库将 Markdown 文档转换为 HTML,并将其插入到插件弹出页面中以展示文章列表。插件还实现了暗黑模式,以匹配 Xargin 博客的暗黑模式。
这是一个简单的项目说明和 README 文件。您可以根据需要进行修改或扩展。
使用方法有点问题。这个插件只在 https://xargin.com 上使用。文章归档并不是在点击插件图标,而是安装此插件后,在 xargin.com 博客页面的上方导航栏会多一个 Archive 的栏目,点击 Archive 后,就会出现历史文章列表。 原理部分也有点问题。我简单描述一下。它是先通过我写的一个爬虫 xargin-blog-crawler,地址:https://github.com/qcrao/xargin-blog-crawler,将 xargin.com 上的文章都爬下来(每隔1小时),写到一个 md 文件里。同时我在 netlify 上部署了一个站点,这个 md 文件就是托管在这个站点上。当用户点击 Archive 后,插件会请求 netlify 拿到 md 文件,再使用 Showdown 库将 Markdown 文档转换为 HTML。然后将其插入到 archive 页面中以展示历史文章列表。 请据此修改 readme。
README.md:
Xargin Blog Archive Extension
Xargin Blog Archive Extension 是一个轻量级的浏览器插件,用于查看 Xargin 博客的文章归档。它提供了一种简便的方式来查看过去的博客文章列表,并支持暗黑模式。
功能
- 在 Xargin 博客页面上添加文章归档链接
- 支持暗黑模式
- 点击文章标题以访问相应文章
安装
- 克隆或下载此 GitHub 仓库到本地。
- 打开浏览器的扩展程序管理页面。
- 启用“开发者模式”。
- 点击“加载已解压的扩展程序”,选择本地仓库的文件夹。
使用方法
- 在安装插件后,访问 https://xargin.com。
- 在博客页面的上方导航栏中,点击 "Archive"。
- 在弹出的页面中,浏览文章归档。
- 点击文章标题以访问相应文章。
原理
插件通过qcrao/xargin-blog-crawler爬虫从 Xargin 博客中抓取文章。爬虫每隔1小时运行一次,将抓取到的文章写入一个 Markdown 文件。此文件托管在 Netlify 上部署的站点上。
当用户点击 "Archive" 时,插件会请求 Netlify 上的站点以获取 Markdown 文件。接着,插件使用 Showdown 库将 Markdown 文档转换为 HTML,并将其插入到 archive 页面中以展示历史文章列表。
这是根据您的要求修改后的 README 文件。请根据需要进行修改或扩展。
我正在将此插件提交到 chrome web store,请帮我填写说明。 单一用途说明。 要求:扩展程序必须有足够具体且易于理解的单一用途。 需请求权限的理由 权限是一系列已知字符串中的某一个字符串(例如“activeTab”)。要求说明使用 scripting,active Tab,主机权限的理由
单一用途说明:
Xargin Blog Archive Extension 是一个专门用于查看 Xargin 博客文章归档的轻量级浏览器插件。它在 Xargin 博客页面上方导航栏中添加一个 "Archive" 链接,用户可以通过点击该链接轻松查看过去的博客文章列表。
需请求权限的理由:
"scripting" 权限: 该插件需要使用 scripting 权限来向 xargin.com 页面插入脚本。通过这些脚本,插件可以添加 "Archive" 链接并将获取到的文章归档信息插入到页面中。
"activeTab" 权限: 该插件需要使用 activeTab 权限来访问用户当前活动的 xargin.com 页面。这样,插件可以确保只在 xargin.com 上添加 "Archive" 链接,避免对其他网站产生不必要的影响。
主机权限: 该插件需要访问 https://xargin.com/* 来获取文章归档信息。通过请求该主机权限,插件可以确保只在 xargin.com 上运行,从而减少对用户隐私和安全性的影响。