cover

使用RSSHub自制Matataki RSS源 - Part 1

A

[TOC]

更新记录

  1. 2020-09-29 初稿 QmNLjA4ojJfHHEdcsTVb9mCwqyK3yBMtsPBvRHGFtiWv9G
  2. 2020-10-01 增加目录 QmScCcsdUK6Azb733RfztodTuWK1i6PFCsYJNT9D3zkCqK
  3. 2020-10-13 系列文章化

系列目录

介绍

瞬Matataki[1]是永久存储和版权确权的内容平台,面向所有写作爱好者和专家媒体。[2]

RSSHub是一个开源、简单易用、易于扩展的 RSS 生成器,可以给任何奇奇怪怪的内容生成 RSS 订阅源。[3]

Matataki官方站点没有提供RSS订阅源,不过有提供API[4]。我们可以使用RSSHub将一些我们感兴趣的内容制作成RSS订阅源,这样就可以统一阅读了。

前置准备

  • 准备一个RSS Reader,本文使用的是Mozilla Thunderbird[5]
  • 搭建Node.js开发环境
  • 申请github账号,fork一份RSSHub的源码,git clone到本地开发环境

开始

进入RSSHub工程目录,npm install安装依赖、npm run dev启动调试模式。打开 http://localhost:1200 就可以看到效果,修改文件也会自动刷新

热门文章订阅源

API信息

GET https://api.smartsignature.io/posts/scoreRanking

实现步骤

  1. 创建lib/routes/matataki/posts/scoreranking.js文件,内容如下:
const got = require('@/utils/got');

module.exports = async (ctx) => {

    const response = await got({
        method: 'get',
        url: `https://api.smartsignature.io/posts/scoreRanking`,
        headers: {
            Referer: 'https://www.matataki.io/',
        },
    });

    const data = response.data;

    ctx.state.data = {
        title: `瞬Matataki - 热门文章`,
        link: `https://www.matataki.io/article/`,
        description: `瞬Matataki - 热门文章`,
        item: data.data.list.map((item) => ({
                title: `${item.title} - ${item.nickname}`,
                description: item.short_content,
                link: `https://www.matataki.io/p/${item.id}`,
            })),
    };
};

整个逻辑还是比较简单的,从API响应数据体里把需要的数据取出来,映射到RSS规范指定的字段里就可以了。
可能产生疑惑的地方是data.data这部分,第一个data是响应数据体对象,第二个data是因为响应数据体报文里用了data这个字段,对照json看应该会更加清晰:

//整个数据就是第一个data
{
  "code":0,
  "message":"成功",
  "data":{ //这里是第二个data
      "count":3621,
      "list":[
          {
              "id":4333,
              "uid":1108,
              "author":"b****************@g*ail.com",
              "title":"1111",
              "status":0,
              "hash":"QmYoNzoAzDNxayyXNZV3DyKvZaEtFLyHdEYFdnT44PcFUo",
              "create_time":"2020-06-11T07:14:35.000Z",
              "cover":"/image/2020/06/11/b47bd713de3733bccefd1de5da08a84c.png",
              "require_holdtokens":0,
              "require_buy":0,
              "short_content":"111",
              "nickname":"billchen",
              "avatar":"/avatar/2020/06/11/44b0fc8693b9155c8b7970d97cae0a68.jpg",
              "read":8,
              "likes":0,
              "pay_platform":null,
              "pay_symbol":null,
              "pay_price":null,
              "pay_decimals":null,
              "pay_stock_quantity":null,
              "token_id":null,
              "token_amount":null,
              "token_name":null,
              "token_symbol":null,
              "token_decimals":null,
              "tags":[{
                      "id":768,
                      "name":"哈尔滨工业大学",
                      "type":"post"
                  }]
          }
      ]
  }
}
  1. lib/router.js文件里增加新的路由信息
// 瞬Matataki
// 热门文章
router.get('/matataki/posts/scoreranking', require('./routes/matataki/posts/scoreranking'));

  1. 打开http://localhost:1200/matataki/posts/scoreranking,如果能看到XML格式的RSS订阅源,就说明成功了

  2. 用RSS Reader订阅,看看效果:

https://ssimg.frontenduse.top/article/2020/09/29/b157e427818a1b10918391b972521a72.png

许多RSS Reader都提供文件夹和tag等功能,可以按照自己喜欢的方式来标记、组织,如图:

https://ssimg.frontenduse.top/article/2020/09/29/928470211d2e616457cba285d7a9cbac.png

IPFS网关版本

Matataki作为去中心化内容发布平台,核心特性之一就是:会自动将所有发布在本平台的文章上传至IPFS网络,以实现分布式存储,保障数据安全。这些数据将不可被篡改,因此将Matataki用作为内容的存证工具也是诸多创作者的应用场景之一。为了让大家可以信任我们的确在IPFS上进行存储,瞬Matataki为所有的文章内容都提供了分布式入口,其中包含了3个IPFS节点的访问入口,任何人都可以查看、验证、保存文章在链上的唯一HASH(相当于内容独一无二的身份证ID)。[6]

也就是说,我们完全可以不经由matataki主站来访问文章,这也是去中心化的体现。配合上述提到的RSS Reader的操作,只要拿到HASH,就可以自行组织数据了

  1. 创建lib/routes/matataki/ipfs/posts/scoreranking.js文件,内容如下:
const got = require('@/utils/got');

const IPFS_GATEWAY_URL = 'https://ipfs.io';

module.exports = async (ctx) => {

    const response = await got({
        method: 'get',
        url: `https://api.smartsignature.io/posts/scoreRanking`,
        headers: {
            Referer: 'https://www.matataki.io/',
        },
    });

    const data = response.data;
    const items = await Promise.all(data.data.list.map(async (item) => {
        const ipfsInfoResponse = await got({
            method: 'get',
            url: `https://api.smartsignature.io/p/${item.id}/ipfs`,
            headers: {
                Referer: 'https://www.matataki.io/',
            },
        });

        const ipfsHtmlHash = ipfsInfoResponse.data.data[0].htmlHash;

        return {
            title: `${item.title} - ${item.nickname}`,
            description: item.short_content,
            link: `${IPFS_GATEWAY_URL}/ipfs/${ipfsHtmlHash}`,
            guid: ipfsHtmlHash,
        };

    }));

    ctx.state.data = {
        title: `瞬Matataki - 热门文章(IPFS)`,
        link: IPFS_GATEWAY_URL,
        description: `瞬Matataki - 热门文章(IPFS)`,
        item: items,
    };
};

关键是IPFS Hash的获取。不能直接使用热门文章API数据条目的Hash,这点要注意。

这里的网关地址用了IPFS官方提供的,完全可以使用其他节点,比如Matataki站点的文章都有提供的三个公共节点的地址

https://ssimg.frontenduse.top/article/2020/09/29/064637adcd4c136faffa5f8b674fab98.png

https://ssimg.frontenduse.top/article/2020/09/29/7f6c1d7f23b5889484137a781e670763.png

截图来源:火锅协议 🍲 POT Finance

  1. lib/router.js文件里增加新的路由信息
// 热门文章-IPFS
router.get('/matataki/ipfs/posts/scoreranking', require('./routes/matataki/ipfs/posts/scoreranking'));

后续的步骤类似,把url换一下就可以了。效果上的区别就是完整文章的url是指向IPFS网关的,不依赖于具体的某个站点

https://ssimg.frontenduse.top/article/2020/09/29/c4f502a54df2e18d77839083bfe05940.png

Fan票关联文章订阅源

这个对应的数据是Fan票圈子的,把这个做成RSS源就可以把自己关注的Fan票聚合在一个界面来跟进了

API信息

GET https://api.smartsignature.io/minetoken/{tokenId}/related

实现步骤

  1. 创建lib/routes/matataki/minetoken/related.js文件,内容如下:
const got = require('@/utils/got');

const MATATAKI_WEB_URL = 'https://www.matataki.io/';

module.exports = async (ctx) => {

    const id = ctx.params.id;
    const query = ctx.params.query;

    const response = await got({
        method: 'get',
        // query filter: 1-需持票; 2-需支付; 3-全部;
        url: `https://api.smartsignature.io/minetoken/${id}/related?${query}`,
        headers: {
            Referer: MATATAKI_WEB_URL,
        },
    });

    const data = response.data;

    ctx.state.data = {
        title: `瞬Matataki - Fan票关联文章`,
        link: `https://www.matataki.io/article/`,
        description: `瞬Matataki - Fan票关联文章`,
        allowEmpty: true,
        item: data.data.list.map((item) => ({
                title: `${item.title} - ${item.nickname} - ${item.token_name}`,
                description: item.short_content,
                link: `https://www.matataki.io/p/${item.id}`,
            })),
    };

};


  1. lib/router.js文件里增加新的路由信息
// Fan票关联
router.get('/matataki/minetoken/:id/related', require('./routes/matataki/minetoken/related'));

这里的:id就是tokenId了,在订阅的时候传入Fan票对应的id就可以了,id可以在Fan票页面url里找到,比如岛岛币的页面url是:https://www.matataki.io/token/22 ,那就写22

同时,我们传入了query,这个query对应API的query

  1. 打开http://localhost:1200/matataki/minetoken/22/related?filter=3&sort=time-desc,如果能看到XML格式的RSS订阅源,就说明成功了

  2. 用RSS Reader订阅几个Fan票关联文章,看看效果:

https://ssimg.frontenduse.top/article/2020/09/29/0d51a40728c741abce3c866da3d96b16.png

IPFS网关版本

基本思路是一样的,新增路由为:

router.get('/matataki/ipfs/minetoken/:id/related', require('./routes/matataki/ipfs/minetoken/related'));

对应/matataki/ipfs/minetoken/related.js实现为:

const got = require('@/utils/got');

const MATATAKI_WEB_URL = 'https://www.matataki.io/';
const IPFS_GATEWAY_URL = 'https://ipfs.io';

module.exports = async (ctx) => {

    const id = ctx.params.id;
    const query = ctx.params.query;

    const response = await got({
        method: 'get',
        // query filter: 1-需持票; 2-需支付; 3-全部;
        url: `https://api.smartsignature.io/minetoken/${id}/related?${query}`,
        headers: {
            Referer: MATATAKI_WEB_URL,
        },
    });

    const data = response.data;
    const items = await Promise.all(data.data.list.map(async (item) => {
        const ipfsInfoResponse = await got({
            method: 'get',
            url: `https://api.smartsignature.io/p/${item.id}/ipfs`,
            headers: {
                Referer: 'https://www.matataki.io/',
            },
        });

        const ipfsHtmlHash = ipfsInfoResponse.data.data[0].htmlHash;

        return {
            title: `${item.title} - ${item.nickname}`,
            description: item.short_content,
            link: `${IPFS_GATEWAY_URL}/ipfs/${ipfsHtmlHash}`,
            guid: ipfsHtmlHash,
        };

    }));


    ctx.state.data = {
        title: `瞬Matataki - Fan票关联文章`,
        link: `https://www.matataki.io/article/`,
        description: `瞬Matataki - Fan票关联文章`,
        allowEmpty: true,
        item: items,
    };

};

效果如图:

https://ssimg.frontenduse.top/article/2020/09/29/0df65c91f8d78773797f96ed635190a8.png

这个场景的主要问题在于,不持有Fan票的情况下这个Hash对应的IPFS里的数据也是不完整的,意义有限。更合适的方案可能是自己搭建一个Matataki前端服务,把url指向该服务提供的页面?

进一步的应用

极端情况下,API服务、站点全部不可用,文章也没导出,自己也没有手动记录IPFS Hash的习惯,本地数据也完蛋的话,有通过链上数据形成某种索引的办法吗?
目前想到一种做法,以收藏夹为例,把【我的收藏】制作成一个RSS源,对应的API应该是这个:

GET https://api.smartsignature.io/user/bookmarks?pagesize=5&page=1

Huginn[7]搭一个触发器,每当这个Feed有更新就把最新的Feed内容提交到IPFS,然后开一个交易把这份文档的Hash写到链上,通过链来找回……也许能作为一种服务吧

小结

  • 初步体验了Matataki的API,无需鉴权的公共API也能有不错的玩法。加上定期获取新的accessToken的逻辑的话,在自建的RSSHub服务上制作个人数据相关的订阅源应该也不难
  • 尝试扩展了一点RSS的使用场景。订阅发布机制和web3.0的基础设施感觉还是能有不错的配合的,有Podcast那样的扩展语义和专用客户端的话,感觉有潜力可挖
  • 验证了即使API服务和站点全部不可用了,RSS定期拉取列表的话,之前有订阅的数据还是有办法找回并组织起来的
  • API提供的各种数据是以什么方式存储的,果然还是会在意呢
  • 认识有限,文章疏漏之处在所难免,欢迎指出。也欢迎讨论各种想法

参考


  1. Matataki主站 ↩︎

  2. Matataki是什么 ↩︎

  3. RSSHub ↩︎

  4. Matataki开发文档 ↩︎

  5. Thunderbird ↩︎

  6. 关于Matataki的内容存储和安全性 ↩︎

  7. Huginn ↩︎

本文发布于瞬matataki, 本文使用 知识共享 署名-非商业性使用-相同方式共享 4.0 协议 请遵守协议许可进行转载

免责声明:本文由用户「WhyYouAre」上传发布,内容为作者独立观点。不代表瞬Matataki立场,不构成投资建议,请谨慎对待。

Loading...
Price:
暂无价格
简 介:

Nothing

已持有:

0

喜欢就打赏Fan票吧~

avatar
0/500
评论0 打赏0