Skip to content

Commit

Permalink
Merge pull request #948 from DIYgod/master
Browse files Browse the repository at this point in the history
[pull] master from diygod:master
  • Loading branch information
pull[bot] authored May 9, 2023
2 parents 6f8c2a2 + c6c8ac0 commit 52e8e14
Show file tree
Hide file tree
Showing 28 changed files with 709 additions and 7 deletions.
54 changes: 54 additions & 0 deletions docs/blog.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,60 @@ username 为博主用户名,而非`xxx.hashnode.dev`中`xxx`所代表的 blog

<RouteEn author="5upernova-heng" example="/macmenubar/recently/developer-apps,system-tools" path="/macmenubar/recently/:category?" :paramsDesc="['分类名,多个使用逗号隔开,留空则为全部。分类名可在 URL 中找到']" radar="1" />

## Medium

### List

<Route author="ImSingee" example="/medium/list/imsingee/f2d8d48096a9" path="/medium/list/:user/:catalogId" :paramsDesc="['用户名', 'List 的 ID']">

List ID 取的是网址中最后一部分 `-` 后面的内容,例如 `https://medium.com/@imsingee/list/collection-7e67004f23f9` 的用户名为 imsingee、ID 为 `7e67004f23f9`

::: warning 注意

想要获取 Private 的 List 则只支持自建

:::

</Route>

### 个性推荐 - For You

<Route author="ImSingee" example="/medium/for-you/imsingee" path="/medium/for-you/:user" :paramsDesc="['用户名']" selfhost="1">

::: warning 注意

个性推荐需要登录后的 Cookie 值,所以只能自建,详情见部署页面的配置模块。

:::

</Route>

### 个性推荐 - Following

<Route author="ImSingee" example="/medium/following/imsingee" path="/medium/following/:user" :paramsDesc="['用户名']" selfhost="1">

::: warning 注意

个性推荐需要登录后的 Cookie 值,所以只能自建,详情见部署页面的配置模块。

:::

</Route>

### 个性推荐 - Tag

<Route author="ImSingee" example="/medium/tag/imsingee/cybersecurity" path="/medium/tag/:user/:tag" :paramsDesc="['用户名', '订阅的 Tag']" selfhost="1">

Tag 有很多,可从首页点进 Tag 以后的 URL 获取,例如 `https://medium.com/?tag=web3` 则 tag 为 `web3`

::: warning 注意

个性推荐需要登录后的 Cookie 值,所以只能自建,详情见部署页面的配置模块。

:::

</Route>

## Miris Whispers

### 博客
Expand Down
54 changes: 54 additions & 0 deletions docs/en/blog.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,60 @@ pageClass: routes

<RouteEn author="5upernova-heng" example="/macmenubar/recently/developer-apps,system-tools" path="/macmenubar/recently/:category?" :paramsDesc="['Category path name, seperate by comma, default is all categories. Category path name can be found in url']" radar="1" />

## Medium

### List

<RouteEn author="ImSingee" example="/medium/list/imsingee/f2d8d48096a9" path="/medium/list/:user/:catalogId" :paramsDesc="['Username', 'List ID']">

The List ID is the last part of the URL after `-`, for example, the username in "https://medium.com/@imsingee/list/collection-7e67004f23f9" is `imsingee`, and the ID is `7e67004f23f9`.

::: warning Note

To access private lists, only self-hosting is supported.

:::

</RouteEn>

### Personalized Recommendations - For You

<RouteEn author="ImSingee" example="/medium/for-you/imsingee" path="/medium/for-you/:user" :paramsDesc="['Username']" selfhost="1">

::: warning Note

Personalized recommendations require the cookie value after logging in, so only self-hosting is supported. See the configuration module on the deployment page for details.

:::

</RouteEn>

### Personalized Recommendations - Following

<RouteEn author="ImSingee" example="/medium/following/imsingee" path="/medium/following/:user" :paramsDesc="['Username']" selfhost="1">

::: warning Note

Personalized recommendations require the cookie value after logging in, so only self-hosting is supported. See the configuration module on the deployment page for details.

:::

</RouteEn>

### Personalized Recommendations - Tag

<RouteEn author="ImSingee" example="/medium/tag/imsingee/cybersecurity" path="/medium/tag/:user/:tag" :paramsDesc="['Username', 'Subscribed Tag']" selfhost="1">

There are many tags, which can be obtained by clicking on a tag from the homepage and looking at the URL. For example, if the URL is `https://medium.com/?tag=web3`, then the tag is `web3`.

::: warning Note

Personalized recommendations require the cookie value after logging in, so only self-hosting is supported. See the configuration module on the deployment page for details.

:::

</RouteEn>

## Miris Whispers

### Blog
Expand Down
5 changes: 5 additions & 0 deletions docs/en/install/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,11 @@ See docs of the specified route and `lib/config.js` for detailed information.
- `MASTODON_API_ACCESS_TOKEN`: user access token
- `MASTODON_API_ACCT_DOMAIN`: acct domain for particular instance
- Medium related routes: Open the console, copy the cookie (in theory, only uid and sid are required)
- `MEDIUM_ARTICLE_COOKIE`: Cookie used when requesting the full article, can access the full text of paid content when there is an active Member subscription.
- `MEDIUM_COOKIE_{username}`: Cookie of the user corresponding to the username, required for personalized recommendation related routes.
- nhentai torrent: [Registration](https://nhentai.net/register/)
- `NHENTAI_USERNAME`: nhentai username or email
Expand Down
10 changes: 9 additions & 1 deletion docs/en/joinus/debug.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ sidebarDepth: 0
---
# Debugging

When debugging your code, you can use more than just `console.log` or attaching the node process to a debugger. Another option is to use `ctx.state.json` to provide a custom object for debugging.
When debugging your code, you can use more than just `console.log` or attaching the node process to a debugger. You can also use the following methods for debugging.

Note: The following methods are only effective when the instance is running with `debugInfo=true`.

## Using `ctx.state.json`

Expand All @@ -24,3 +26,9 @@ ctx.state.json = {
```

In the example above, we're passing the `info` object to `ctx.state.json`, which we can then access using the corresponding route + `.debug.json`.

## debug.html

In order to quickly test if the `description` in `ctx.state.data` is correct, you can use the `.debug.html` file suffix to obtain the HTML of the corresponding entry. The link can be directly opened in the browser to preview the rendering result.

Usage: Access the corresponding route + `.{index}.debug.html`, where `{index}` is the item number (starting from 0) in your `ctx.state.data.item`. And the data corresponds to the `ctx.state.data.item[index].description` information will be returned as route result.
11 changes: 10 additions & 1 deletion docs/en/parameter.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ E.g.
- JSON Feed - [https://rsshub.app/twitter/user/DIYgod.json](https://rsshub.app/twitter/user/DIYgod.json)
- Apply filters or URL query - [https://rsshub.app/dribbble/popular.atom?filterout=Blue|Yellow|Black](https://rsshub.app/dribbble/popular.atom?filterout=Blue|Yellow|Black)

### Debug
### debug.json

If the RSSHub instance is running with `debugInfo=true` enabled, suffixing a route with `.debug.json` will result in the value of `ctx.state.json` being returned.

Expand All @@ -158,6 +158,15 @@ For example:

- `/furstar/characters/cn.debug.json`

### debug.html

By adding `.{index}.debug.html` (where `{index}` is a number starting from 0) at the end of the route and running the instance with `debugInfo=true`, RSSHub will return the content set in the plugin's `ctx.state.data.item[index].description`. You can access this page with a browser to quickly view the extracted information.

Example:

- `/furstar/characters/cn.0.debug.html`


## Brief introduction

Set the parameter `brief` to generate a brief pure-text introduction with a limited number of characters ( ≥ `100`).
Expand Down
5 changes: 5 additions & 0 deletions docs/install/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,11 @@ RSSHub 支持使用访问密钥 / 码,白名单和黑名单三种方式进行
- `MASTODON_API_ACCESS_TOKEN`: 用户 access token, 申请应用后,在应用配置页可以看到申请者的 access token
- `MASTODON_API_ACCT_DOMAIN`: 该实例本地用户 acct 标识的域名

- Medium 相关路由:打开控制台,复制 Cookie(理论上只需要 uid 和 sid 即可)

- `MEDIUM_ARTICLE_COOKIE`:请求全文时使用的 Cookie,存在活跃的 Member 订阅时可获取付费内容全文
- `MEDIUM_COOKIE_{username}`:对应 username 的用户的 Cookie,个性推荐相关路由需要

- MiniFlux 全部路由:

- `MINIFLUX_INSTANCE`: 用户所用的实例,默认为 MiniFlux 官方提供的 [付费服务地址](https://reader.miniflux.app)
Expand Down
10 changes: 9 additions & 1 deletion docs/joinus/debug.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ sidebarDepth: 0
---
# 调试

当调试代码时,除了使用 `console.log` 或将 node 进程附加到调试器,您还可以将自定义对象提供给 `ctx.state.json` 来进行调试。
当调试代码时,除了使用 `console.log` 或将 node 进程附加到调试器,您还可以使用如下方式进行调试。

注意:需要实例运行在 `debugInfo=true` 的情况下以下方式才有效

## 使用 `ctx.state.json`

Expand All @@ -24,3 +26,9 @@ ctx.state.json = {
```

在上面的示例中,我们将 `info` 对象传递给 `ctx.state.json`,然后可以使用相应的路由 + `.debug.json` 来访问它。

## debug.html

为了快速测试 `ctx.state.data` 中的 description 是否正确,你可以利用 `debug.html` 机制来获取相关条目的 HTML,该链接可以直接在浏览器中打开以预览渲染结果。

使用方式:访问相应的路由 + `.{index}.debug.html`,其中 `{index}` 为你的 `ctx.state.data.item` 中的项目序号(从 0 开始),即返回对应路由结果中的 `ctx.state.data.item[index].description` 信息。
10 changes: 9 additions & 1 deletion docs/parameter.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ RSSHub 同时支持 RSS 2.0、Atom 和 JSON Feed 输出格式,在路由末尾
- JSON Feed - <https://rsshub.app/twitter/user/DIYgod.json>
- 和 filter 或其他 URL query 一起使用 - `https://rsshub.app/bilibili/user/coin/2267573.atom?filter=微小微|赤九玖|暴走大事件`

### debug
### debug.json

在路由末尾添加 `.debug.json`且实例运行在`debugInfo=true`的情况下,RSShub 将会返回插件设置在`ctx.state.json`的内容

Expand All @@ -157,6 +157,14 @@ RSSHub 同时支持 RSS 2.0、Atom 和 JSON Feed 输出格式,在路由末尾

- `/furstar/characters/cn.debug.json`

### debug.html

在路由末尾添加 `.{index}.debug.html``{index}` 为数字,为从 0 开始的下标)且实例运行在 `debugInfo=true` 的情况下,RSShub 将会返回插件设置在 `ctx.state.data.item[index].description` 的内容,你可用浏览器访问该页面来快速查看提取的信息的展示结果。

举例:

- `/furstar/characters/cn.0.debug.html`

## 输出简讯

可以使用 `brief` 参数输出特定字数 ( ≥ `100` 字 ) 的纯文本内容
Expand Down
14 changes: 14 additions & 0 deletions docs/university.md
Original file line number Diff line number Diff line change
Expand Up @@ -3750,3 +3750,17 @@ jsjxy.hbut.edu.cn 证书链不全,自建 RSSHub 可设置环境变量 NODE_TLS
### 数据科学与计算机学院动态

<Route author="Neutrino3316 MegrezZhu nczitzk" example="/sysu/cse" path="/sysu/cse"/>

### 粤港澳发展研究院

<Route author="TonyRL" example="/sysu/ygafz" path="/sysu/ygafz/:type?" :paramsDesc="['分类,见下表,默认为 `notice`']" radar="1" puppeteer="1">

| 人才招聘 | 人才培养 | 新闻动态 | 通知公告 | 专家观点 |
| ---------- | ------------- | -------- | -------- | -------- |
| jobopening | personnelplan | news | notice | opinion |

| 研究成果 | 研究论文 | 学术著作 | 形势政策 |
| -------- | -------- | -------- | -------- |
| results | papers | writings | policy |

</Route>
8 changes: 8 additions & 0 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const calculateValue = () => {
const twitter_tokens = {};
const email_config = {};
const discuz_cookies = {};
const medium_cookies = {};

for (const name in envs) {
if (name.startsWith('BILIBILI_COOKIE_')) {
Expand All @@ -23,6 +24,9 @@ const calculateValue = () => {
} else if (name.startsWith('DISCUZ_COOKIE_')) {
const cid = name.slice(14);
discuz_cookies[cid] = envs[name];
} else if (name.startsWith('MEDIUM_COOKIE_')) {
const username = name.slice(14).toLowerCase();
medium_cookies[username] = envs[name];
}
}

Expand Down Expand Up @@ -208,6 +212,10 @@ const calculateValue = () => {
accessToken: envs.MASTODON_API_ACCESS_TOKEN,
acctDomain: envs.MASTODON_API_ACCT_DOMAIN,
},
medium: {
cookies: medium_cookies,
articleCookie: envs.MEDIUM_ARTICLE_COOKIE || '',
},
miniflux: {
instance: envs.MINIFLUX_INSTANCE || 'https://reader.miniflux.app',
token: envs.MINIFLUX_TOKEN || '',
Expand Down
15 changes: 14 additions & 1 deletion lib/middleware/template.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { art, json } = require('@/utils/render');
const path = require('path');
const config = require('@/config').value;
const typeRegex = /\.(atom|rss|debug\.json|json)$/;
const typeRegex = /\.(atom|rss|debug\.json|json|\d+\.debug\.html)$/;
const { collapseWhitespace, convertDateToISO8601 } = require('@/utils/common-utils');

module.exports = async (ctx, next) => {
Expand All @@ -26,6 +26,19 @@ module.exports = async (ctx, next) => {
ctx.body = JSON.stringify({ message: 'plugin does not set debug json' });
}
}
if (outputType.endsWith('.debug.html') && config.debugInfo) {
ctx.set({
'Content-Type': 'text/html; charset=UTF-8',
});

const index = parseInt(outputType.match(/(\d+)\.debug\.html$/)[1]);
if (!(ctx.state.data && ctx.state.data.item && ctx.state.data.item[index])) {
ctx.body = `ctx.state.data.item[${index}] not found`;
} else {
ctx.body = ctx.state.data.item[index].description;
}
}

if (outputType === 'json') {
ctx.set({ 'Content-Type': 'application/feed+json; charset=UTF-8' });
}
Expand Down
2 changes: 1 addition & 1 deletion lib/v2/gov/ccdi/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module.exports = async (ctx) => {
pathname = pathname === '' ? defaultPath : pathname.endsWith('/') ? pathname : pathname + '/';
const currentUrl = `${rootUrl}${pathname}`;

const { list, title } = await parseNewsList(currentUrl, '.list_news_dl li', ctx);
const { list, title } = await parseNewsList(currentUrl, '.list_news_dl2 li', ctx);
const items = await Promise.all(list.map((item) => parseArticle(item, ctx)));

ctx.state.data = {
Expand Down
2 changes: 1 addition & 1 deletion lib/v2/gov/ccdi/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const parseNewsList = async (url, selector, ctx) => {
return {
title: item.find('a').first().text().trim(),
link: new URL(item.find('a').first().attr('href'), url).href,
pubDate: parseDate(item.find('span').text(), 'YYYY-MM-DD'),
pubDate: parseDate(item.find('.more').text(), 'YYYY-MM-DD'),
};
});
const title = $('.other_Location')
Expand Down
31 changes: 31 additions & 0 deletions lib/v2/medium/following.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const config = require('@/config').value;

const parseArticle = require('./parse-article.js');
const { getFollowingFeedQuery } = require('./graphql.js');

module.exports = async (ctx) => {
const user = ctx.params.user;

const cookie = config.medium.cookies[user];
if (cookie === undefined) {
throw Error(`缺少 Medium 用户 ${user} 登录后的 Cookie 值`);
}

const posts = await getFollowingFeedQuery(user, cookie);
ctx.state.json = posts;

if (!posts) {
// login failed
throw Error(`Medium 用户 ${user} 的 Cookie 无效或已过期`);
}

const urls = posts.items.map((data) => data.post.mediumUrl);

const parsedArticles = await Promise.all(urls.map((url) => parseArticle(ctx, url)));

ctx.state.data = {
title: `${user} Medium Following`,
link: 'https://medium.com/?feed=following',
item: parsedArticles,
};
};
31 changes: 31 additions & 0 deletions lib/v2/medium/for-you.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const config = require('@/config').value;

const parseArticle = require('./parse-article.js');
const { getWebInlineRecommendedFeedQuery } = require('./graphql.js');

module.exports = async (ctx) => {
const user = ctx.params.user;

const cookie = config.medium.cookies[user];
if (cookie === undefined) {
throw Error(`缺少 Medium 用户 ${user} 登录后的 Cookie 值`);
}

const posts = await getWebInlineRecommendedFeedQuery(user, cookie);
ctx.state.json = posts;

if (!posts) {
// login failed
throw Error(`Medium 用户 ${user} 的 Cookie 无效或已过期`);
}

const urls = posts.items.map((data) => data.post.mediumUrl);

const parsedArticles = await Promise.all(urls.map((url) => parseArticle(ctx, url)));

ctx.state.data = {
title: `${user} Medium For You`,
link: 'https://medium.com/',
item: parsedArticles,
};
};
Loading

1 comment on commit 52e8e14

@vercel
Copy link

@vercel vercel bot commented on 52e8e14 May 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.