<?xml version='1.0' encoding='UTF-8'?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0"><channel><title>神觉晓</title><link>https://shenjuexiao.com</link><description>@shenjuexiao</description><copyright>神觉晓</copyright><docs>http://www.rssboard.org/rss-specification</docs><generator>python-feedgen</generator><image><url>https://github.githubassets.com/favicons/favicon.svg</url><title>avatar</title><link>https://shenjuexiao.com</link></image><lastBuildDate>Sat, 18 Jul 2026 08:42:00 +0000</lastBuildDate><managingEditor>神觉晓</managingEditor><ttl>60</ttl><webMaster>神觉晓</webMaster><item><title>actions-gh-pages</title><link>https://shenjuexiao.com/post/7.html</link><description># actions-gh-pages

## 内容来源

- [actions-gh-pages](https://github.com/peaceiris/actions-gh-pages)
-  [GitHub凭证区别](https://chat.deepseek.com/share/37lldwwwu2m7wobum4)[（Deepseek）](https://chat.deepseek.com/a/chat/s/351bd0f3-9c56-42f0-ac38-91bf90c0e184)
-  [GitHub令牌区别](https://chat.deepseek.com/share/8m05dxz9pqrkl0wo8s)[（Deepseek）](https://chat.deepseek.com/a/chat/s/26baece4-d43e-48eb-81d4-d6de0ece8f04)

actions-gh-pages 这个项目非常不错，利用 `Github Actions` 部署静态页面。</description><guid isPermaLink="true">https://shenjuexiao.com/post/7.html</guid><pubDate>Sat, 18 Jul 2026 08:41:32 +0000</pubDate></item><item><title>Astro Template</title><link>https://shenjuexiao.com/post/6.html</link><description># Astro 模板
## Astro Paper
![satnaing/astro-paper](https://cdn.jsdelivr.net/gh/shenjuexiao/shenjuexiao@main/Github_png/Astro_Template_satnaing_astro-paper.png)
高评分、暗黑模式、RSS/SEO 完善 
Demo: [astro-paper.pages.dev](https://astro-paper.pages.dev/)  
Github: [satnaing/astro-paper](https://github.com/satnaing/astro-paper)

## Astrofy
![manuelernestog/astrofy](https://cdn.jsdelivr.net/gh/shenjuexiao/shenjuexiao@main/Github_png/Astro_Template_manuelernestog_astrofy.png)
含简历/商店/博客多合一，CV+ 项目画廊  
Demo: [astrofy-template.netlify.app](https://astrofy-template.netlify.app/)  
Github: [manuelernestog/astrofy](https://github.com/manuelernestog/astrofy)

## EV0
![gndx/ev0-astro-theme](https://cdn.jsdelivr.net/gh/shenjuexiao/shenjuexiao@main/Github_png/Astro_Template_gndx_ev0-astro-theme.png)
极简响应式
Demo: [ev0.gndx.dev](https://ev0.gndx.dev/)  
Github: [withastro/starlight](https://github.com/gndx/ev0-astro-theme)

## Firefly
![CuteLeaf/Firefly](https://cdn.jsdelivr.net/gh/shenjuexiao/shenjuexiao@main/Github_png/Astro_Template_CuteLeaf_Firefly.png)
专为技术文档设计，支持多语言、搜索、版本切换
Demo: [firefly.cuteleaf.cn](https://firefly.cuteleaf.cn/)  
Github: [CuteLeaf/Firefly](https://github.com/CuteLeaf/Firefly)  
Docs: [docs-firefly.cuteleaf.cn](https://docs-firefly.cuteleaf.cn/zh/)

## Pure
![cworld1/astro-theme-pure](https://cdn.jsdelivr.net/gh/shenjuexiao/shenjuexiao@main/Github_png/Astro_Template_cworld1_astro-theme-pure.png)
极简 + 全文搜索  
Demo: [astro-pure.js.org](https://astro-pure.js.org/)  
Github: [cworld1/astro-theme-pure](https://github.com/cworld1/astro-theme-pure)
&gt; 这位作者的 Github 主页，可以追溯到 1990 年，不知道怎么弄出来的。</description><guid isPermaLink="true">https://shenjuexiao.com/post/6.html</guid><pubDate>Sat, 18 Jul 2026 05:02:40 +0000</pubDate></item><item><title>The requested URL returned error: 403</title><link>https://shenjuexiao.com/post/5.html</link><description># The requested URL returned error: 403

# GitHub Actions push 403 权限拒绝解决

## 内容来源

- [豆包：GitHub Actions 403](https://www.doubao.com/chat/38434639772911618)
- [The requested URL returned error: 403](https://github.com/shenjuexiao/giscafer/issues/1)

&lt;img src='https://cdn.jsdelivr.net/gh/shenjuexiao/shenjuexiao@main/Github_png/Giscafer_GitHub_Actions_push_403.png' /&gt;

## fatal: unable to access

```yaml
Run yarn sync-post
  yarn sync-post
  git add .
  git commit -m 'chore(ci): blog sync'
  git push
  shell: /usr/bin/bash -e {0}
  env:
    GH_TOKEN: ***
    GH_USER: ***
    GH_PROJECT_NAME: ***
yarn run v1.22.22
$ node ./scripts/sync-post.js
文章全部同步成功！ 0
Done in 0.33s.
ℹ No staged files found.
[main 7226b3a] chore(ci): blog sync
 3 files changed, 33 deletions(-)
 delete mode 100644 data/blog/post-1.mdx
 delete mode 100644 data/blog/post-2.mdx
 delete mode 100644 data/blog/post-3.mdx
remote: Permission to ***/***.git denied to github-actions[bot].
fatal: unable to access 'https://github.com/***/***/': The requested URL returned error: 403
Error: Process completed with exit code 128.
```

## 文件：`.github/workflows/sync-post.yml`
```yaml
name: Sync Post

# Controls when the workflow will run
on:
  # schedule:
  #   - cron: '30 1 * * *'
  # https://docs.github.com/cn/developers/webhooks-and-events/events/issue-event-types
  issues:
    types:
      - opened
      - closed
      - renamed
      - labeled
      - unlabeled
      - reopened
      - committed # 修改？
  workflow_dispatch:
env:
  GH_TOKEN: ${{ secrets.GH_TOKEN }}
  GH_USER: ${{ secrets.GH_USER }}
  GH_PROJECT_NAME: ${{ secrets.GH_PROJECT_NAME }}
jobs:
  Publish:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout 🛎️
        uses: actions/checkout@v2

      - name: Git config 🔧
        run: |
          git config --global user.name 'shenjuexiao'
          git config --global user.email 'shenjuexiao@qq.com'

      - name: Display runtime info ✨
        run: |
          echo '当前目录：'
          pwd

      - name: Install 🔧
        run: yarn install

      # - name: Build ⛏️
      #   run: yarn build

      - name: Update blog files ⛏️
        run: |
          yarn sync-post
          git add .
          git commit -m 'chore(ci): blog sync'
          git push
```

**github-actions[bot]** 没有仓库写入推送权限，触发 403 forbidden。</description><guid isPermaLink="true">https://shenjuexiao.com/post/5.html</guid><pubDate>Tue, 14 Jul 2026 15:15:02 +0000</pubDate></item><item><title>Gitblog main.py</title><link>https://shenjuexiao.com/post/4.html</link><description># Gitblog main.py

## 内容来源

- [Deepseek：#Gitblog main.py 代码解析](https://chat.deepseek.com/share/0k49t8521q3gk2acx9)
- [The requested URL returned error: 403](https://github.com/shenjuexiao/giscafer/issues/1)

## main.py

```python
# main.py
# -*- coding: utf-8 -*-
import argparse
import os
import re

import markdown
from feedgen.feed import FeedGenerator
from github import Github
from lxml.etree import CDATA
from marko.ext.gfm import gfm as marko

MD_HEAD = '''## [Gitblog](https://yihong0618.github.io/gitblog/)
My personal blog([About Me](https://github.com/yihong0618/gitblog/issues/282)) using issues and GitHub Actions (随意转载，无需署名)
[Things I like](https://github.com/yihong0618/gitblog/issues/311)
![image](https://github.com/user-attachments/assets/a168bf11-661e-4566-b042-7fc9544de528)
[RSS Feed](https://raw.githubusercontent.com/{repo_name}/master/feed.xml)
'''

BACKUP_DIR = 'BACKUP'
ANCHOR_NUMBER = 5
TOP_ISSUES_LABELS = ['Top']
TODO_ISSUES_LABELS = ['TODO']
FRIENDS_LABELS = ['Friends']
ABOUT_LABELS = ['About']
THINGS_LABELS = ['Things']
IGNORE_LABELS = (
    FRIENDS_LABELS
    + TOP_ISSUES_LABELS
    + TODO_ISSUES_LABELS
    + ABOUT_LABELS
    + THINGS_LABELS
)

FRIENDS_TABLE_HEAD = '| Name | Link | Desc | \n | ---- | ---- | ---- |\n'
FRIENDS_TABLE_TEMPLATE = '| {name} | {link} | {desc} |\n'
FRIENDS_INFO_DICT = {
    '名字': '',
    '链接': '',
    '描述': '',
}


def get_me(user):
    return user.get_user().login


def is_me(issue, me):
    return issue.user.login == me


def is_hearted_by_me(comment, me):
    reactions = list(comment.get_reactions())
    for r in reactions:
        if r.content == 'heart' and r.user.login == me:
            return True
    return False


def _make_friend_table_string(s):
    info_dict = FRIENDS_INFO_DICT.copy()
    try:
        string_list = s.splitlines()
        # drop empty line
        string_list = [l for l in string_list if l and not l.isspace()]
        for l in string_list:
            string_info_list = re.split('：', l)
            if len(string_info_list) &lt; 2:
                continue
            info_dict[string_info_list[0]] = string_info_list[1]
        return FRIENDS_TABLE_TEMPLATE.format(
            name=info_dict['名字'], link=info_dict['链接'], desc=info_dict['描述']
        )
    except Exception as e:
        print(str(e))
        return


# help to covert xml vaild string
def _valid_xml_char_ordinal(c):
    codepoint = ord(c)
    # conditions ordered by presumed frequency
    return (
        0x20 &lt;= codepoint &lt;= 0xD7FF
        or codepoint in (0x9, 0xA, 0xD)
        or 0xE000 &lt;= codepoint &lt;= 0xFFFD
        or 0x10000 &lt;= codepoint &lt;= 0x10FFFF
    )


def format_time(time):
    return str(time)[:10]


def login(token):
    return Github(token)


def get_repo(user: Github, repo: str):
    return user.get_repo(repo)


def parse_TODO(issue):
    body = issue.body.splitlines()
    todo_undone = [l for l in body if l.startswith('- [ ] ')]
    todo_done = [l for l in body if l.startswith('- [x] ')]
    # just add info all done
    if not todo_undone:
        return f'[{issue.title}]({issue.html_url}) all done', []
    return (
        f'[{issue.title}]({issue.html_url})--{len(todo_undone)} jobs to do--{len(todo_done)} jobs done',
        todo_done + todo_undone,
    )


def get_top_issues(repo):
    return repo.get_issues(labels=TOP_ISSUES_LABELS)


def get_todo_issues(repo):
    return repo.get_issues(labels=TODO_ISSUES_LABELS)


def get_repo_labels(repo):
    return [l for l in repo.get_labels()]


def get_issues_from_label(repo, label):
    return repo.get_issues(labels=(label,))


def add_issue_info(issue, md):
    time = format_time(issue.created_at)
    md.write(f'- [{issue.title}]({issue.html_url})--{time}\n')


def add_md_todo(repo, md, me):
    todo_issues = list(get_todo_issues(repo))
    if not TODO_ISSUES_LABELS or not todo_issues:
        return
    with open(md, 'a+', encoding='utf-8') as md:
        md.write('## TODO\n')
        for issue in todo_issues:
            if is_me(issue, me):
                todo_title, todo_list = parse_TODO(issue)
                md.write('TODO list from ' + todo_title + '\n')
                for t in todo_list:
                    md.write(t + '\n')
                # new line
                md.write('\n')


def add_md_top(repo, md, me):
    top_issues = list(get_top_issues(repo))
    if not TOP_ISSUES_LABELS or not top_issues:
        return
    with open(md, 'a+', encoding='utf-8') as md:
        md.write('## 置顶文章\n')
        for issue in top_issues:
            if is_me(issue, me):
                add_issue_info(issue, md)


def add_md_firends(repo, md, me):

    s = FRIENDS_TABLE_HEAD
    friends_issues = list(repo.get_issues(labels=FRIENDS_LABELS))
    if not FRIENDS_LABELS or not friends_issues:
        return
    friends_issue_number = friends_issues[0].number
    for issue in friends_issues:
        for comment in issue.get_comments():
            if is_hearted_by_me(comment, me):
                try:
                    s += _make_friend_table_string(comment.body or '')
                except Exception as e:
                    print(str(e))
                    pass
    s = markdown.markdown(s, output_format='html', extensions=['extra'])
    with open(md, 'a+', encoding='utf-8') as md:
        md.write(
            f'## [友情链接](https://github.com/{str(me)}/gitblog/issues/{friends_issue_number})\n'
        )
        md.write('&lt;details&gt;&lt;summary&gt;显示&lt;/summary&gt;\n')
        md.write(s)
        md.write('&lt;/details&gt;\n')
        md.write('\n\n')


def add_md_recent(repo, md, me, limit=5):
    count = 0
    with open(md, 'a+', encoding='utf-8') as md:
        # one the issue that only one issue and delete (pyGitHub raise an exception)
        try:
            md.write('## 最近更新\n')
            for issue in repo.get_issues(sort='created', direction='desc'):
                if is_me(issue, me):
                    add_issue_info(issue, md)
                    count += 1
                    if count &gt;= limit:
                        break
        except Exception as e:
            print(str(e))


def add_md_header(md, repo_name):
    with open(md, 'w', encoding='utf-8') as md:
        md.write(MD_HEAD.format(repo_name=repo_name))
        md.write('\n')


def add_md_label(repo, md, me):
    labels = get_repo_labels(repo)

    # sort lables by description info if it exists, otherwise sort by name,
    # for example, we can let the description start with a number (1#Java, 2#Docker, 3#K8s, etc.)
    labels = sorted(
        labels,
        key=lambda x: (
            x.description is None,
            x.description == '',
            x.description,
            x.name,
        ),
    )

    with open(md, 'a+', encoding='utf-8') as md:
        for label in labels:
            # we don't need add top label again
            if label.name in IGNORE_LABELS:
                continue

            issues = get_issues_from_label(repo, label)
            issues = list(sorted(issues, key=lambda x: x.created_at, reverse=True))
            if len(issues) != 0:
                md.write('## ' + label.name + '\n\n')
            i = 0
            for issue in issues:
                if not issue:
                    continue
                if is_me(issue, me):
                    if i == ANCHOR_NUMBER:
                        md.write('&lt;details&gt;&lt;summary&gt;显示更多&lt;/summary&gt;\n')
                        md.write('\n')
                    add_issue_info(issue, md)
                    i += 1
            if i &gt; ANCHOR_NUMBER:
                md.write('&lt;/details&gt;\n')
                md.write('\n')


def get_to_generate_issues(repo, dir_name, issue_number=None):
    md_files = os.listdir(dir_name)
    generated_issues_numbers = [
        int(i.split('_')[0]) for i in md_files if i.split('_')[0].isdigit()
    ]
    to_generate_issues = [
        i
        for i in list(repo.get_issues())
        if int(i.number) not in generated_issues_numbers
    ]
    if issue_number:
        to_generate_issues.append(repo.get_issue(int(issue_number)))
    return to_generate_issues


def generate_rss_feed(repo, filename, me):
    generator = FeedGenerator()
    generator.id(repo.html_url)
    generator.title(f'RSS feed of {repo.owner.login}'s {repo.name}')
    generator.author(
        {'name': os.getenv('GITHUB_NAME'), 'email': os.getenv('GITHUB_EMAIL')}
    )
    generator.link(href=repo.html_url)
    generator.link(
        href=f'https://raw.githubusercontent.com/{repo.full_name}/master/{filename}',
        rel='self',
    )
    for issue in repo.get_issues():
        if not issue.body or not is_me(issue, me) or issue.pull_request:
            continue
        item = generator.add_entry(order='append')
        item.id(issue.html_url)
        item.link(href=issue.html_url)
        item.title(issue.title)
        item.published(issue.created_at.strftime('%Y-%m-%dT%H:%M:%SZ'))
        for label in issue.labels:
            item.category({'term': label.name})
        body = ''.join(c for c in issue.body if _valid_xml_char_ordinal(c))
        item.content(CDATA(marko.convert(body)), type='html')
    generator.atom_file(filename)


def main(token, repo_name, issue_number=None, dir_name=BACKUP_DIR):
    user = login(token)
    me = get_me(user)
    repo = get_repo(user, repo_name)
    # add to readme one by one, change order here
    add_md_header('README.md', repo_name)
    for func in [add_md_firends, add_md_top, add_md_recent, add_md_label, add_md_todo]:
        func(repo, 'README.md', me)

    generate_rss_feed(repo, 'feed.xml', me)
    to_generate_issues = get_to_generate_issues(repo, dir_name, issue_number)

    # save md files to backup folder
    for issue in to_generate_issues:
        save_issue(issue, me, dir_name)


def save_issue(issue, me, dir_name=BACKUP_DIR):
    md_name = os.path.join(
        dir_name, f'{issue.number}_{issue.title.replace('/', '-').replace(' ', '.')}.md'
    )
    with open(md_name, 'w') as f:
        f.write(f'# [{issue.title}]({issue.html_url})\n\n')
        f.write(issue.body or '')
        if issue.comments:
            for c in issue.get_comments():
                if is_me(c, me):
                    f.write('\n\n---\n\n')
                    f.write(c.body or '')


if __name__ == '__main__':
    if not os.path.exists(BACKUP_DIR):
        os.mkdir(BACKUP_DIR)
    parser = argparse.ArgumentParser()
    parser.add_argument('github_token', help='github_token')
    parser.add_argument('repo_name', help='repo_name')
    parser.add_argument(
        '--issue_number', help='issue_number', default=None, required=False
    )
    options = parser.parse_args()
    main(options.github_token, options.repo_name, options.issue_number)
```


这是一个使用GitHub Issues作为博客系统的Python脚本，名为Gitblog。</description><guid isPermaLink="true">https://shenjuexiao.com/post/4.html</guid><pubDate>Tue, 14 Jul 2026 15:13:57 +0000</pubDate></item><item><title>Gmeek Deploy</title><link>https://shenjuexiao.com/post/3.html</link><description># Gmeek 部署

## 内容来源
- [Gmeek快速上手](https://blog.meekdai.com/post/Gmeek-kuai-su-shang-shou.html)
- [Gmeek 部署](https://github.com/gaishanke/gaishanke.github.io/issues/3)

## Gmeek 博客框架
- 超轻量级个人博客模板
- 完全基于 `Github Pages` 、 `Github Issues` 和 `Github Actions`，
- 不需要本地部署

## 一、资源

## Gmeek
- [Gmeek快速上手](https://blog.meekdai.com/post/Gmeek-kuai-su-shang-shou.html)  
- [Gmeek Github 源码](https://github.com/Meekdai/Gmeek)

### Markdown 语法
- [Basic writing and formatting syntax](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax)  
- [基本撰写和格式语法](https://docs.github.com/zh/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax)

### 在线编辑工具
- [markdown.com.cn](https://markdown.com.cn/editor/)

## 二、安装

### 创建仓库
- 点击[通过模板创建仓库](https://github.com/new?template_name=Gmeek-template&amp;template_owner=Meekdai)，仓库名称：`&lt;用户名&gt;.github.io`

### 启用 Pages
- 仓库页面导航：`Settings` -&gt; `Pages` -&gt; `Build and deployment`
- `Source` 下拉选择 `Github Actions`

&lt;img src='https://cdn.jsdelivr.net/gh/shenjuexiao/shenjuexiao@main/Github_png/Gmeek_Settings_Github-Pages_Github-Actions.png' /&gt;

### 开始写作
- 仓库页面导航：`Issues` -&gt; `New issue`
- `Add a title`（写标题），`Add a description`（写描述）。</description><guid isPermaLink="true">https://shenjuexiao.com/post/3.html</guid><pubDate>Tue, 14 Jul 2026 11:44:53 +0000</pubDate></item><item><title>Github Issues Blog List</title><link>https://shenjuexiao.com/post/2.html</link><description># Github Issues 博客项目（不完全统计）

## 内容来源

- [Github Issues 搭建的博客项目列表](https://github.com/gaishanke/gaiashanke.github.io/issues/2)

## @rena.to/github-blog

-   **技术栈**：TypeScript（核心API库）
-   **项目链接**：[https://www.npmjs.com/package/@rena.to/github-blog](https://www.npmjs.com/package/@rena.to/github-blog)

## AllanChain/blog

-   **技术栈**：Astro
-   **项目链接**：[https://github.com/AllanChain/blog](https://github.com/AllanChain/blog)

## babilema

-   **技术栈**：Go（静态博客生成器）
-   **项目链接**：[https://pkg.go.dev/github.com/ByteBakersCo/babilema](https://pkg.go.dev/github.com/ByteBakersCo/babilema)

## ginb

-   **技术栈**：Next.js, Tailwind CSS, React
-   **项目链接**：[https://github.com/ChrAlpha/ginb](https://github.com/ChrAlpha/ginb)

## gitblog

-   **技术栈**：Python
-   **项目链接**：[https://github.com/yihong0618/gitblog](https://github.com/yihong0618/gitblog)

## gitblog

-   **技术栈**：JavaScript
-   **项目链接**：[https://github.com/imuncle/gitblog](https://github.com/imuncle/gitblog)

## Gmeek

-   **技术栈**：GitHub Pages, GitHub Actions, jinja2, primer.style
-   **项目链接**：[https://github.com/Ambop/Gmeek](https://github.com/Ambop/Gmeek)

## Issue-Blog-With-Github-Action

-   **技术栈**：Vuepress
-   **项目链接**：[https://github.com/Yidadaa/Issue-Blog-With-Github-Action](https://github.com/Yidadaa/Issue-Blog-With-Github-Action)

## qiwihui/blog

-   **技术栈**：CSS
-   **项目链接**：[https://github.com/qiwihui/blog](https://github.com/qiwihui/blog)

## Sep0lkit/git-issues-blog

-   **技术栈**：Python
-   **项目链接**：[https://github.com/Sep0lkit/git-issues-blog](https://github.com/Sep0lkit/git-issues-blog)

## ttop5/issue-blog

-   **技术栈**：Vue
-   **项目链接**：[https://github.com/ttop5/issue-blog](https://github.com/ttop5/issue-blog)

## whyour/issue-blog

-   **技术栈**：TypeScript（VS Code插件）
-   **项目链接**：[https://github.com/whyour/issue-blog](https://github.com/whyour/issue-blog)

## xizhibei/blog

-   **技术栈**：Node.js, Golang
-   **项目链接**：[https://github.com/xizhibei/blog](https://github.com/xizhibei/blog)。</description><guid isPermaLink="true">https://shenjuexiao.com/post/2.html</guid><pubDate>Tue, 14 Jul 2026 11:44:22 +0000</pubDate></item><item><title>Github Issues Blog Gitblog</title><link>https://shenjuexiao.com/post/1.html</link><description># Gitblog

用过 Jekyll、Hexo，捣鼓了一阵子，都没能长期使用持续写作，现在转头使用 GIthub Issue 搭建的博客系统。</description><guid isPermaLink="true">https://shenjuexiao.com/post/1.html</guid><pubDate>Tue, 14 Jul 2026 11:43:56 +0000</pubDate></item></channel></rss>