关于友情链接和 SSG 在博客中展示 Flux 订阅

关于友情链接和 SSG 在博客中展示 Flux 订阅

April 15, 2024
工具箱 , 分享 , 编码 ,

友情链接

此前我一直以文章内容的形式手动展示和维护博客的友链,并在文中附上了友情链接添加的条件,此间也收到过不少好友的链接申请。

不过在 2023 年 11 月 05 日 ,我对该页面的介绍做了更新,并在文中写到:

今天忽然发现我好像重新理解的「友邻」的意义,这个邻居应该是我喜欢、欣赏的,对我有「正面影响」的,而不是冰冷页面上的一个超链接而已。

所以我决定只在这个页面展示我喜欢的博客,我也并不需要他们也给我做上「友情链接」,单纯只是因为我喜欢、欣赏他们。

另外那些没有出现在这个页面上的朋友也不要心有芥蒂,并不是你的博客不优秀,毕竟「喜欢」这个词非常主观不是吗?

自那之后我就再没有对友情链接页面中的链接做过维护。

并且在之后不久基于 23 年 11 月 5 日的见解 博客并不是页面上的一个超链接 ,我希望能 通过他们的博客获取一些正向激励 ,而且是 持续 性的获得这种激励。

所以我开始认真 使用 订阅工具,此间还分享了 打破信息茧房及一款 RSS 阅读器推荐如何订阅 Q 外的 RSS?方法来了 两文。

更换工具

不过文中介绍到的订阅工具 yarr 因为是开发者自己做的一个工具,虽然这个工具确实兼容了多平台,但是在手机上的使用体验非常别扭,如下图所示:

因为我是习惯左手玩手机,所以在使用 yarr 时阅读完一篇文章后需要点击最右上角的关闭才能关闭,对于目前的只能手机尺寸来说这个操作是及其别扭的。

所以我在前不久正式切换到了 miniflux ,这是一款及其简单、专注的 web 端 self-host 订阅工具,并有着强大的扩展功能,开发者也十分活跃,之前没有选他主要是因为原生界面实在是太丑了。

不过前些日子看到 蜗牛大佬 推荐了一款 miniflux 的主题 Miniflux-Theme-Reeder ,所以心动 + yarr 的不适之下进行了更换。

不过本文不详述如何安装,有时间会更新在我的 数字花园

友链链接改为展示订阅

在后续的使用过程中发现了 miniflux 的强大拓展能力,所以想着能不能将我的博客订阅在友情页面内展示,经过一番研究和 ChatGPT 沟通后,后终于完整实现了这个功能,所以本文假定你已符合以下条件:

  • 已安装和正常使用 miniflux
  • 使用 ssg,最好是 11ty
  • 有一定的程序基础。

一、 生成 API 密钥

在 miniflux 的 keys 页面中可以生成用于访问 API 的 Token,并复制备用。

二、本地调试可以配置 11ty 项目环境变量

为了避免暴露,我们将 token 变量写入 vscode 的 launch.js 文件中,并在 .gitignore 文件中添加 .vscode/ 文件夹。

{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node-terminal",
            "request": "launch",
            "name": "启动程序",
            "command": "yarn run start",
            "cwd": "${workspaceFolder}",
            "env": {
                "FLUX_TOKEN": "你的token" //将变量写入env中
            }
        }
    ]
}

并在 11ty 中使用 process.env.FLUX_TOKEN 调用。

const fluxToken = process.env.FLUX_TOKEN;

三、Github 上配置环境变量

同理,为了能顺利使用 Github Action 生成网站,并部署到 Netlify 上,我们还需要设置 Github Action 变量,具体位置为 Github 上的 11ty 项目中的 /settings/secrets/action 下,添加同名 FLUX_TOKEN 变量即可。

同时修改 Github Action 文件,在 build 命令中使用该变量。

on: 
  repository_dispatch:
    types:
      - update
  schedule:
    - cron: '0 2 * * *' 
    
jobs:
  build_deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master

      - name: Set Node.js 20.x
        uses: actions/setup-node@master
        with:
          node-version: 20.x        

      - name: Run install
        uses: borales/actions-yarn@v4
        with:
          cmd: install # will run `yarn install` command

      - name: Build production bundle
        uses: borales/actions-yarn@v4
        env:
          FLUX_TOKEN: ${{secrets.FLUX_TOKEN}} #设置在Build过程中需要使用的FLUX_TOKEN
        with:
          cmd: prod # will run `yarn prod` command


      - name: Deploy to Netlify
        uses: netlify/actions/cli@master
        env:
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
          build_directory: dist
        with:
          args: deploy --prod

代码实现

至此已经完成了变量配置操作,接下来是代码实现部分,这里以 11ty 为例,其他 SSG 程序可以根据程序自身特性更换实现方式。

根据 miniflux 的 API 文档 我们可以使用 get-category-entries 接口获取文章数据,请求格式为 下方所示:

GET /v1/categories/22/entries?limit=1&order=id&direction=asc
  • 其中 22 为分类编号,可以在 flux 中点击对应分类,url 中的数字部分就是了。
  • limit 则是获取多少个订阅。
  • order 排序

不过获取的数据似乎是所有的文章数据,所以需要进行一次筛选操作。

我这里只希望展示最新的一条文章,根据和 ChatGPT 的交流,通过 Filter 过出所有博客最新的一条数据。

  //... .eleventy.js
  // Get All feeds
    config.addCollection("feeds", async function (collection) {
        if (fluxToken) {
            try {
                // 请求
                const response = await fetch(
                    "https://flux.1900.live/v1/categories/4/entries?order=id&direction=desc&limit=99999",
                    {
                        method: "GET",
                        headers: {
                            "X-Auth-Token": fluxToken,
                        },
                    }
                );
                let data = await response.json();
                data = data.entries.filter((entry, index, self) => {
                    // 因为flux中订阅网站的site_url有时候会是rss地址,所以这里做了一下处理,只获取 https://xxxx.com 部分,方便访客跳转访问。
                    const domain = new URL(entry.feed.site_url).origin;
                    entry.feed.site_url = domain;
                    return (
                        self.findIndex(
                            (item) => item.feed_id === entry.feed_id
                        ) === index
                    );
                });
                return data;
            } catch (error) {
                console.log("请求错误:", error);
            }
        }
        return collection;
    });

接下来在 11ty 的模板中遍历数据即可。

<article class="markdown book-article">
  <h2 class="book-title">
    我关注的博主们
  </h2>
  <div class="book-columns flex flex-wrap">
  {% for item in collections.feeds %}
    <div class="flex-even markdown-inner">
      <h3 class="ellipsis"><a href="{{item.feed.site_url}}" target="_blank">{{item.feed.title}}</a></h3>
      <div><span>{{ item.published_at | htmlDate   }}</span></div>
      <div class="ellipsis"><a href="{{item.url}}" target="_blank">{{item.title}}</a></div>
    </div> 
  {% endfor %}
  </div>
</div>

效果可以看本站 https://1900.live/links/ 页面。

加入评论