banner
cover

使用RSSHub自制Matataki RSS源 - Part 2

A

[TOC]

更新记录

  1. 2020-10-10 初稿 QmUGbHSqSrMgKUwKHFkeZjovrF9NXv2auEHbLFgbZtsyvP
  2. 2020-10-13 增加系列目录 QmT7tPygKSpP5jrUh87H7T6UVoxXXCy3qzax3tB2mmmG76
  3. 2020-10-14 调整用语;实现RSSHub Radar规则;新增主题订阅源实现

系列目录

概述

上一篇文章介绍了使用RSSHub自制Matataki RSS源的方法。实际使用一段时间后,发现了一些痛点,尝试解决,并做个记录

存在问题

代码重复

首先对之前的实现做一下分析:

通过对比几个路由脚本实现,我们会发现,整体逻辑其实都一样:

  1. 调用API,获取到数据
  2. 把数据转换为RSS Feed格式来消费

用到的API语义上都是各种get,只是url不同;
上述API的条目都是对应Matataki上的文章,所以item的格式也都是非常类似的,Feed Item需要的字段基本都能直接拿到;
IPFS版本则是因为需要获取Hash,中间需要多调一个API,这段代码都是一样的,可以很简单地提取出函数。

Feed标题重复

Fan票关联文章这类Feed,之前的方案是在文章标题里加上了作者昵称 ${item.title} - ${item.nickname},通过作者来区分来源。这样文章是可以区分开了,但是订阅源多了还是不好管理。最好每个订阅源的title都带上Fan票的名称,即 瞬Matataki - ${tokenName}关联文章 这种格式

Feed缓存

RSSHub本身是有缓存的,RSS Reader本身也有影响,可能不会把只是querystring不同的部分当成不同的订阅源,两者共同作用下只根据querystring来区分数据的API不能直接套查询条件,要在url上下点功夫

Feed Link不准确

官网版Feed之前统一连到首页文章去了,针对具体语义找更合适的url

具体实现

按照重构的思路,把各种通用逻辑封装成一个工具:

lib/utils/matataki-utils.js


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

/**
 *  Matataki 官网地址
 */
const MATATAKI_WEB_URL = 'https://www.matataki.io/';

/**
 *  IPFS网关的URL。可以换成其他公共网关,也可以换成自建的网关地址
 */
const IPFS_GATEWAY_URL = 'https://ipfs.io';

/**
 * 以`get` 方式调用Matataki API的简单封装
 *
 * @param {string} url
 */
async function get(url) {
    return await got({
        method: 'get',
        url: url,
        headers: {
            Referer: MATATAKI_WEB_URL,
        },
    });
}

exports.IPFS_GATEWAY_URL = IPFS_GATEWAY_URL;

exports.get = get;

/**
 * 获取用户信息昵称
 *
 * @param {number} userId
 */
exports.getUserNickname = async (userId) => {
    try {
        const userInfoResponse = await get(`https://api.smartsignature.io/user/${userId}`);
        return `${userInfoResponse.data.data.nickname}`;
    }
    catch (err) {
        return '';
    }
};


/**
 * 获取Fan票名称
 *
 * @param {number} tokenId
 */
exports.getTokenName = async (tokenId) => {
    try {
        const tokenInfoResponse = await get(`https://api.smartsignature.io/minetoken/${tokenId}`);
        return `${tokenInfoResponse.data.data.token.name}`;
    }
    catch (err) {
        return '';
    }
};

/**
 * 获取Matataki文章在IPFS上的Hash
 *
 * @param {number} postId
 */
exports.getPostIpfsHtmlHash = async (postId) => {
    const ipfsInfoResponse = await get(`https://api.smartsignature.io/p/${postId}/ipfs`);
    return `${ipfsInfoResponse.data.data[0].htmlHash}`;
};

/**
 * 将Matataki文章条目转为指向IPFS网关的RSS订阅源条目
 *
 * @param {Object} item
 */
exports.postToIpfsFeedItem = async (item) => {

    const ipfsHtmlHash = await this.getPostIpfsHtmlHash(item.id);

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

};

/**
 * 将Matataki文章条目转为指向官网的RSS订阅源条目
 *
 * @param {Object} item
 */
exports.postToFeedItem = (item) => ({
    title: `${item.title} - ${item.nickname}`,
    description: item.short_content,
    link: `https://www.matataki.io/p/${item.id}`,
});

/**
 * 获取文章列表并转为IPFS Feed Item 数组
 *
 * @param {string} url Matataki文章相关API的url
 */
exports.getPostIpfsFeedItems = async (url) => {
    const response = await get(url);
    return await Promise.all(response.data.data.list.map(this.postToIpfsFeedItem));
};

/**
 * 获取文章列表并转为Feed Item数组
 *
 * @param {string} url Matataki文章相关API的url
 */
exports.getPostFeedItems = async (url) => {
    const response = await get(url);
    return response.data.data.list.map(this.postToFeedItem);
};


各个Feed都基于这个来实现,每个Feed只关注自己需要提供的内容

热门作品

官网版

lib/routes/matataki/posts/scoreranking.js

const matatakiUtils = require('@/utils/matataki-utils');

module.exports = async (ctx) => {

    const items = await matatakiUtils.getPostFeedItems(`https://api.smartsignature.io/posts/scoreRanking`);

    ctx.state.data = {
        title: `瞬Matataki - 热门作品`,
        link: `https://www.matataki.io/article/`,
        description: `瞬Matataki - 热门作品`,
        item: items
    };
};

IPFS版

lib/routes/ipfs/matataki/posts/scoreranking.js

const matatakiUtils = require('@/utils/matataki-utils');

module.exports = async (ctx) => {

    const items = await matatakiUtils.getPostIpfsFeedItems(`https://api.smartsignature.io/posts/scoreRanking`);

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

Fan票关联作品

官网版

lib/routes/matataki/minetoken/related.js

const matatakiUtils = require('@/utils/matataki-utils');

module.exports = async (ctx) => {

    const id = ctx.params.id;
    const querystring = ctx.request.querystring;

    const tokenName = await matatakiUtils.getTokenName(id);
    const items = await matatakiUtils.getPostFeedItems(`https://api.smartsignature.io/minetoken/${id}/related?${querystring}`);

    ctx.state.data = {
        title: `瞬Matataki - ${tokenName ? tokenName : 'Fan票'}关联作品`,
        link: `https://www.matataki.io/token/${id}/circle`,
        description: `瞬Matataki - ${tokenName ? tokenName : 'Fan票'}关联作品`,
        allowEmpty: true,
        item: items,
    };

};

大体上就是填模板

IPFS版

lib/routes/ipfs/matataki/minetoken/related.js

const matatakiUtils = require('@/utils/matataki-utils');

module.exports = async (ctx) => {

    const id = ctx.params.id;
    const querystring = ctx.request.querystring;

    const tokenName = await matatakiUtils.getTokenName(id);
    const items = await matatakiUtils.getPostIpfsFeedItems(`https://api.smartsignature.io/minetoken/${id}/related?${querystring}`);

    ctx.state.data = {
        title: `瞬Matataki - ${tokenName ? tokenName : 'Fan票'}关联作品(IPFS)`,
        link: matatakiUtils.IPFS_GATEWAY_URL,
        description: `瞬Matataki - ${tokenName ? tokenName : 'Fan票'}关联作品(IPFS)`,
        allowEmpty: true,
        item: items,
    };

};

高度相似,Feed里title link description的不同算是刻意为之的

作者创作

追更具体的作者也是很常见的需求,这里就基于新版本的方式实现一下

调用API

GET https://api.smartsignature.io/posts/timeRanking?author=${authorId}

路由配置

这个authorId在订阅源地址里要放在path部分,否则同时订阅多个作者的时候可能会有问题

lib/router.js里增加的路由信息如下:

router.get('/matataki/user/:authorId/posts', require('./routes/matataki/posts/author'));

路由实现

lib/routes/matataki/posts/author.js

const matatakiUtils = require('@/utils/matataki-utils');

module.exports = async (ctx) => {

    const authorId = ctx.params.authorId;

    const authorName = await matatakiUtils.getUserNickname(authorId);

    const items = await matatakiUtils.getPostFeedItems(`https://api.smartsignature.io/posts/timeRanking?author=${authorId}`);

    ctx.state.data = {
        title: `瞬Matataki - ${authorName}作品`,
        link: `https://www.matataki.io/user/${authorId}`,
        description: `瞬Matataki - ${authorName}作品`,
        item: items,
    };
};

和Fan票类似,为了区分不同的作者订阅源,在titledescription里标明了作者。

IPFS版也只需要把getPostFeedItems换成getIpfsPostFeedItems就可以用了,Feed的link也可以像上面的IPFS版一样换成matatakiUtils.IPFS_GATEWAY_URL

效果

https://ssimg.frontenduse.top/article/2020/10/10/2c249f78f4387c0711b48f5b89a14a6d.png

订阅源对应的作者变得很清楚了

https://ssimg.frontenduse.top/article/2020/10/10/5cc46383315593a13bad9e825e74bd7d.png

这实质就成为一个收件箱,熟悉GTD等方法的,可以把这个纳入自己的工作流[1]

主题作品

基于tag来订阅

调用API

GET https://api.smartsignature.io/posts/getPostByTag?pagesize=20&tagid=${tagId}&extra=short_content&orderBy=hot_score&order=desc&page=1

路由配置

这个tagId在订阅源地址里要放在path部分,否则同时订阅多个主题的时候可能会有问题

lib/router.js里增加的路由信息如下:

router.get('/matataki/tags/:tagId/posts', require('./routes/matataki/posts/tag'));

路由实现

lib/routes/matataki/posts/tag.js

const matatakiUtils = require('@/utils/matataki-utils');

module.exports = async (ctx) => {

    const tagId = ctx.params.tagId;
    const tagName = ctx.request.query.name;

    const items = await matatakiUtils.getPostFeedItems(`https://api.smartsignature.io/posts/getPostByTag?pagesize=20&tagid=${tagId}&extra=short_content&orderBy=hot_score&order=desc&page=1`);

    ctx.state.data = {
        title: `瞬Matataki #${tagName}`,
        link: `https://www.matataki.io/tags/${tagId}`,
        description: `瞬Matataki #${tagName}`,
        item: items,
    };
};

和Fan票类似,为了区分不同的主题订阅源,在titledescription里标明了主题名称。

IPFS版也只需要把getPostFeedItems换成getIpfsPostFeedItems就可以用了,Feed的link也可以像上面的IPFS版一样换成matatakiUtils.IPFS_GATEWAY_URL

效果

https://ssimg.frontenduse.top/article/2020/10/14/e83d55778f9da1c1b36e2aee160c42b1.png

RSSHub Radar[2]

开发环境直接在Radar的源文件里添加规则

src/js/common/radar-rules.js

export default {
    'matataki.io': {
        _name: 'matataki',
        www: [
            {
                title: '最热作品',
                docs: 'https://docs.rsshub.app/new-media.html#matataki',
                source: ['/article', '/article/latest'],
                target: '/matataki/posts/scoreranking'
            },
            {
                title: '最新作品',
                docs: 'https://docs.rsshub.app/new-media.html#matataki',
                source: ['/article', '/article/latest'],
                target: '/matataki/posts/timeranking'
            },
            {
                title: '作者创作',
                docs: 'https://docs.rsshub.app/new-media.html#matataki',
                source: '/user/:uid',
                target: (params) => `/matataki/user/${params.uid}/posts`
            },
            {
                title: 'Fan票关联作品',
                docs: 'https://docs.rsshub.app/new-media.html#matataki',
                source: ['/token/:tid', '/token/:tid/circle'],
                target: (params) => `/matataki/minetoken/${params.tid}/related/3`
            },
            {
                title: '主题作品',
                docs: 'https://docs.rsshub.app/new-media.html#matataki',
                source: ['/tags/:tagId'],
                target: (params,url) => `/matataki/tags/${params.tagId}/posts?name=${new URL(url).searchParams.get('name')}`
            }
        ]

    },
    ...
    
}    

,‘mpm run build'生成新的dist后,浏览器加载扩展即可食用

最热作品&最新作品

在站点首页就可以检测到,如:https://www.matataki.io/article/

https://ssimg.frontenduse.top/article/2020/10/14/4726886aa7a823337b32b904061248ca.png

Fan票关联作品

在Fan票主页就可以检测到,如:https://www.matataki.io/token/22

https://ssimg.frontenduse.top/article/2020/10/14/0c399c7661c385e8afcc9b0cbba89e08.png

作者创作

在作者主页就可以检测到,如: https://www.matataki.io/user/2421

https://ssimg.frontenduse.top/article/2020/10/14/3132f2fef7f196691c3dfa264926ff9b.png

主题作品

首先在首页找到热门主题,选其中一个tag打开即可检测到,也可以“查看全部”后选择tag打开,如: https://www.matataki.io/tags/265?name=智能合约

https://ssimg.frontenduse.top/article/2020/10/14/395c7d9be9172507e1fc1147062cf850.png

连载类文章设置相同tag的话就可以从一个入口追了

代码仓库

Github仓库地址

和上次相比已经变了不少,感觉还能优化点什么,还是提交到仓库后继续打理下去比较好。

本文涉及的代码修改在feature/matataki分支。

見えるけど見えないもの

下一步

打算把路由文档和RSShub Radar扩展的部分搞定,订阅起来就不用手动找id拼url了,使用起来会更顺滑。

参考资料


  1. 收件箱管理——清空你的收件箱 ↩︎

  2. RSSHub Radar 是 RSSHub 的衍生项目,她是一个可以帮助你快速发现和订阅当前网站 RSS 和 RSSHub 的浏览器扩展 万物皆可 RSS ↩︎

This article was posted on 瞬matataki, This article uses Knowledge Sharing 署名-非商业性使用-相同方式共享 4.0 protocol Please follow the agreement to reprint

Disclaimer: This article was uploaded and published by the user "WhyYouAre", and the content is the author's independent opinion. It does not represent the position of 瞬Matataki and does not constitute investment advice. Please be cautious.

Loading...
Current price:
No price
Introduction

Nothing

Already held:

0

If you like, get a Fan ticket~

avatar
0/500
Comment0 Reward0