diff --git a/docs/en/parameter.md b/docs/en/parameter.md index 908d32480..782890656 100644 --- a/docs/en/parameter.md +++ b/docs/en/parameter.md @@ -48,6 +48,8 @@ Set `filter` to include the content - `filter_author`: filter `author` only +- `filter_category`: filter `category` only + - `filter_time`: filter `pubDate`, in seconds, return specified time range. Item without `pubDate` will not be filtered. E.g. [https://rsshub.app/dribbble/popular?filter=Blue|Yellow|Black](https://rsshub.app/dribbble/popular?filter=Blue|Yellow|Black) @@ -62,6 +64,8 @@ Set `filterout` to exclude unwanted content. - `filterout_author`: filter `author` only +- `filterout_category`: filter `category` only + E.g. [https://rsshub.app/dribbble/popular?filterout=Blue|Yellow|Black](https://rsshub.app/dribbble/popular?filterout=Blue|Yellow|Black) Set `filter_case_sensitive` to determine whether the filtering keywords should be case sensitive. The parameter would apply to both `filter` and `filterout`. diff --git a/docs/parameter.md b/docs/parameter.md index de6878282..f8774d011 100644 --- a/docs/parameter.md +++ b/docs/parameter.md @@ -46,6 +46,8 @@ filter 支持正则表达式。由于正则部分特性可被利用于 DoS (ReDO - `filter_author`: 过滤作者 +- `filter_category`: 过滤分类 + - `filter_time`: 过滤时间,仅支持数字,单位为秒。返回指定时间范围内的内容。如果条目没有输出`pubDate`或者格式不正确将不会被过滤 举例 1: `https://rsshub.app/bilibili/fav/2267573/801952073?filter=编曲|摄影` @@ -61,6 +63,8 @@ filter 支持正则表达式。由于正则部分特性可被利用于 DoS (ReDO - `filterout_author`: 过滤作者 +- `filterout_category`: 过滤分类 + 举例: `https://rsshub.app/bilibili/fav/2267573/801952073?filterout=编曲|摄影` `filter_case_sensitive` 过滤是否区分大小写,`filter` 和 `filterout`同时适用 diff --git a/lib/middleware/parameter.js b/lib/middleware/parameter.js index 68e1ac04f..87a134cf6 100644 --- a/lib/middleware/parameter.js +++ b/lib/middleware/parameter.js @@ -179,26 +179,30 @@ module.exports = async (ctx, next) => { const title = item.title || ''; const description = item.description || title; const author = item.author || ''; - const isFilter = title.match(makeRegex(ctx.query.filter)) || description.match(makeRegex(ctx.query.filter)) || author.match(makeRegex(ctx.query.filter)); + const category = item.category || []; + const isFilter = + title.match(makeRegex(ctx.query.filter)) || description.match(makeRegex(ctx.query.filter)) || author.match(makeRegex(ctx.query.filter)) || category.some((c) => c.match(makeRegex(ctx.query.filter))); return isFilter; }); } - // 启用filter参数时,无效filter_title/description/author - if (!ctx.query.filter && (ctx.query.filter_title || ctx.query.filter_description || ctx.query.filter_author)) { + // 启用filter参数时,无效filter_title/description/author/category + if (!ctx.query.filter && (ctx.query.filter_title || ctx.query.filter_description || ctx.query.filter_author || ctx.query.filter_category)) { ctx.state.data.item = ctx.state.data.item.filter((item) => { const title = item.title || ''; const description = item.description || title; const author = item.author || ''; + const category = item.category || []; let isFilter = true; ctx.query.filter_title && (isFilter = title.match(makeRegex(ctx.query.filter_title))); ctx.query.filter_description && (isFilter = isFilter && description.match(makeRegex(ctx.query.filter_description))); ctx.query.filter_author && (isFilter = isFilter && author.match(makeRegex(ctx.query.filter_author))); + ctx.query.filter_category && (isFilter = isFilter && category.some((c) => c.match(makeRegex(ctx.query.filter_category)))); return isFilter; }); } - if (ctx.query.filterout || ctx.query.filterout_title || ctx.query.filterout_description || ctx.query.filterout_author) { + if (ctx.query.filterout || ctx.query.filterout_title || ctx.query.filterout_description || ctx.query.filterout_author || ctx.query.filterout_category) { if (ctx.query.filterout) { ctx.query.filterout_title = ctx.query.filterout; ctx.query.filterout_description = ctx.query.filterout; @@ -207,10 +211,12 @@ module.exports = async (ctx, next) => { const title = item.title; const description = item.description || title; const author = item.author || ''; + const category = item.category || []; let isFilter = true; ctx.query.filterout_title && (isFilter = !title.match(makeRegex(ctx.query.filterout_title))); ctx.query.filterout_description && (isFilter = isFilter && !description.match(makeRegex(ctx.query.filterout_description))); ctx.query.filterout_author && (isFilter = isFilter && !author.match(makeRegex(ctx.query.filterout_author))); + ctx.query.filterout_category && (isFilter = isFilter && !category.some((c) => c.match(makeRegex(ctx.query.filterout_category)))); return isFilter; }); } diff --git a/lib/v2/test/index.js b/lib/v2/test/index.js index 196ef1fe3..38ebf88ca 100644 --- a/lib/v2/test/index.js +++ b/lib/v2/test/index.js @@ -23,6 +23,7 @@ module.exports = async (ctx) => { pubDate: new Date(`2019-3-1`).toUTCString(), link: `https://github.com/DIYgod/RSSHub/issues/-1`, author: `DIYgod0`, + category: ['Category0', 'Category1'], }, { title: 'Filter Title2', @@ -30,6 +31,7 @@ module.exports = async (ctx) => { pubDate: new Date(`2019-3-1`).toUTCString(), link: `https://github.com/DIYgod/RSSHub/issues/0`, author: `DIYgod0`, + category: ['Category0', 'Category1', 'Category2'], }, ]; } else if (ctx.params.id === 'long') { diff --git a/test/middleware/parameter.js b/test/middleware/parameter.js index bed065215..7d12d954a 100644 --- a/test/middleware/parameter.js +++ b/test/middleware/parameter.js @@ -83,6 +83,28 @@ describe('filter', () => { expect(parsed.items[1].title).toBe('Title5'); }); + it(`filter_category`, async () => { + const response = await request.get('/test/filter?filter_category=Category0|Category1'); + const parsed = await parser.parseString(response.text); + expect(parsed.items.length).toBe(2); + expect(parsed.items[0].title).toBe('Filter Title1'); + expect(parsed.items[1].title).toBe('Filter Title2'); + }); + + it(`filter_category filter_case_sensitive default`, async () => { + const response = await request.get('/test/filter?filter_category=category0|category1'); + const parsed = await parser.parseString(response.text); + expect(parsed.items.length).toBe(0); + }); + + it(`filter_category filter_case_sensitive=false`, async () => { + const response = await request.get('/test/filter?filter_category=category0|category1&filter_case_sensitive=false'); + const parsed = await parser.parseString(response.text); + expect(parsed.items.length).toBe(2); + expect(parsed.items[0].title).toBe('Filter Title1'); + expect(parsed.items[1].title).toBe('Filter Title2'); + }); + it(`filter_time`, async () => { const response = await request.get('/test/current_time?filter_time=25'); const parsed = await parser.parseString(response.text); @@ -185,6 +207,33 @@ describe('filter', () => { expect(parsed.items[2].title).toBe('Title3'); }); + it(`filterout_category`, async () => { + const response = await request.get('/test/filter?filterout_category=Category0|Category1'); + const parsed = await parser.parseString(response.text); + expect(parsed.items.length).toBe(5); + expect(parsed.items[0].title).toBe('Title1'); + expect(parsed.items[1].title).toBe('Title2'); + expect(parsed.items[2].title).toBe('Title3'); + }); + + it(`filterout_category filter_case_sensitive default`, async () => { + const response = await request.get('/test/filter?filterout_category=category0|category1'); + const parsed = await parser.parseString(response.text); + expect(parsed.items.length).toBe(7); + expect(parsed.items[0].title).toBe('Filter Title1'); + expect(parsed.items[1].title).toBe('Filter Title2'); + expect(parsed.items[2].title).toBe('Title1'); + }); + + it(`filterout_category filter_case_sensitive=false`, async () => { + const response = await request.get('/test/filter?filterout_category=category0|category1&filter_case_sensitive=false'); + const parsed = await parser.parseString(response.text); + expect(parsed.items.length).toBe(5); + expect(parsed.items[0].title).toBe('Title1'); + expect(parsed.items[1].title).toBe('Title2'); + expect(parsed.items[2].title).toBe('Title3'); + }); + it(`filter combination`, async () => { const response = await request.get('/test/filter?filter_title=Filter&filter_description=Description1'); const parsed = await parser.parseString(response.text);