Skip to content

feat(route): add southplus forum #22186

Open
NicholasYZ wants to merge 6 commits into
DIYgod:masterfrom
NicholasYZ:feat-southplus
Open

feat(route): add southplus forum #22186
NicholasYZ wants to merge 6 commits into
DIYgod:masterfrom
NicholasYZ:feat-southplus

Conversation

@NicholasYZ

@NicholasYZ NicholasYZ commented Jun 4, 2026

Copy link
Copy Markdown

Involved Issue / 该 PR 相关 Issue

Close #4541

Example for the Proposed Route(s) / 路由地址示例

   /south-plus/forum/8

New RSS Route Checklist / 新 RSS 路由检查表

  • New Route / 新的路由
  • Anti-bot or rate limit / 反爬/频率限制 (PHPwind自身无限制,考虑到CF限制了并发数)
    • If yes, do your code reflect this sign? / 如果有, 是否有对应的措施?
    • p-map 并发控制 (concurrency=3)
    • 完整浏览器请求头 (UA / Accept / Accept-Language / Referer)
  • Date and time / 日期和时间
    • Parsed / 可以解析 (parseDate 解析 YYYY-MM-DD HH:MM)
    • Correct time zone / 时区正确 (UTC+8)
  • New package added / 添加了新的包
  • Puppeteer

Note / 说明

South Plus(南+)添加 RSS 路由。

特性

  • 支持公开和需登录的版块(通过 SOUTHPLUS_COOKIE 环境变量认证)
  • 全文抓取 + cache.tryGet 缓存
  • p-map 并发控制(每次 3 个请求)
  • 路由描述中包含常用 fid 对照表和 Cookie 示例

涉及文件

文件 变更
lib/config.ts +7 行,添加 SOUTHPLUS_COOKIE 配置项
lib/routes/south-plus/namespace.ts 新建,命名空间定义 + Cookie 获取指南
lib/routes/south-plus/forum.ts 新建,路由处理器(188 行)

测试

在docker环境中测试通过

/south-plus/forum/8        → 200 OK, 50 items (公开版块)
/south-plus/forum/128      → 200 OK, 50 items (需 Cookie)

@github-actions github-actions Bot added the route label Jun 4, 2026
@NicholasYZ NicholasYZ changed the title Feat southplus feat(route) add southplus forum Jun 4, 2026
@NicholasYZ NicholasYZ changed the title feat(route) add southplus forum feat(route): add southplus forum Jun 4, 2026
@github-actions github-actions Bot added the auto: not ready to review Users can't get the RSS feed output according to automated testing results label Jun 4, 2026
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Successfully generated as following:

http://localhost:1200/south-plus/forum/8 - Failed ❌
HTTPError: Response code 503 (Service Unavailable)

Error Message:<br/>FetchError: [GET] &quot;https://south-plus.net/thread.php?fid-8.html&quot;: 403
Route: /south-plus/forum/:fid?
Full Route: /south-plus/forum/8
Node Version: v24.16.0
Git Hash: 48f80cef
http://localhost:1200/ /south-plus/forum/128 - Failed ❌
HTTPError: Response code 503 (Service Unavailable)

Error Message:<br/>NotFoundError:
Route: /   /south-plus/forum/128
Full Route: /   /south-plus/forum/128
Node Version: v24.16.0
Git Hash: 48f80cef

@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Auto Review

  • [Rule 8] lib/config.ts: southplus config block is inserted between douban and ehentai in both the Config type (~line 403) and calculateValue (~line 909), but alphabetically south comes after sorrycc and before spotify. Move both blocks to after sorrycc and before spotify in those two locations. (The ConfigEnvKeys union placement is already correct.)

- /south-plus/forum/:fid? for PHPWind-based forum
- Cookie-based auth via SOUTHPLUS_COOKIE env var
- Configurable UA via SOUTHPLUS_UA (cookie-version binding)
- Full-text fetching with cache.tryGet
- p-map concurrency control (3 at a time)
- Category extraction from thread listing
- Fid reference table and cookie guide in description
….trueUA as default

- Replace hardcoded Firefox 151 UA with config.trueUA to comply with guideline 36
- Use built-in proxy.dispatcher (PROXY_URI) for proxy support instead of custom env var
- Update documentation: F12 Network approach for cookie/UA extraction, PROXY_URI tip
- Fix markdown structure: close Cookie tip block before UA tip
@github-actions github-actions Bot added auto: not ready to review Users can't get the RSS feed output according to automated testing results and removed auto: not ready to review Users can't get the RSS feed output according to automated testing results labels Jun 4, 2026
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Successfully generated as following:

http://localhost:1200/south-plus/forum/8 - Failed ❌
HTTPError: Response code 503 (Service Unavailable)

Error Message:<br/>AssertionError: The expression evaluated to a falsy value:

  assert(dispatcher)
Route: /south-plus/forum/:fid?
Full Route: /south-plus/forum/8
Node Version: v24.16.0
Git Hash: f316c16f
http://localhost:1200/ /south-plus/forum/128 - Failed ❌
HTTPError: Response code 503 (Service Unavailable)

Error Message:<br/>NotFoundError:
Route: /   /south-plus/forum/128
Full Route: /   /south-plus/forum/128
Node Version: v24.16.0
Git Hash: f316c16f

@github-actions github-actions Bot added auto: not ready to review Users can't get the RSS feed output according to automated testing results and removed auto: not ready to review Users can't get the RSS feed output according to automated testing results labels Jun 4, 2026
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Successfully generated as following:

http://localhost:1200/south-plus/forum/8 - Failed ❌
HTTPError: Response code 503 (Service Unavailable)

Error Message:<br/>AssertionError: The expression evaluated to a falsy value:

  assert(dispatcher)
Route: /south-plus/forum/:fid?
Full Route: /south-plus/forum/8
Node Version: v24.16.0
Git Hash: f316c16f

…in CI

RSSHub globally overrides globalThis.fetch with proxy auto-injection
via request-rewriter. Passing dispatcher: null (when PROXY_URI is unset)
triggers undici internal assert(dispatcher) failure in GitHub Actions.
@github-actions github-actions Bot added auto: not ready to review Users can't get the RSS feed output according to automated testing results and removed auto: not ready to review Users can't get the RSS feed output according to automated testing results labels Jun 4, 2026
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Successfully generated as following:

http://localhost:1200/south-plus/forum/8 - Failed ❌
HTTPError: Response code 503 (Service Unavailable)

Error Message:<br/>Error: this route is empty, please check the original site or &lt;a href=&quot;https://github.com/DIYgod/RSSHub/issues/new/choose&quot;&gt;create an issue&lt;/a&gt;
Route: /south-plus/forum/:fid?
Full Route: /south-plus/forum/8
Node Version: v24.16.0
Git Hash: 42490282

Comment thread lib/routes/south-plus/forum.ts Outdated
Comment thread lib/routes/south-plus/forum.ts Outdated
Comment thread lib/routes/south-plus/forum.ts Outdated
Comment thread lib/routes/south-plus/forum.ts
Comment thread lib/routes/south-plus/forum.ts Outdated
Comment thread lib/config.ts Outdated

@TonyRL TonyRL left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please update the involved issue section as this PR satifies #4541

Co-authored-by: Tony <TonyRL@users.noreply.github.com>
@github-actions github-actions Bot removed the auto: not ready to review Users can't get the RSS feed output according to automated testing results label Jun 7, 2026
@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Successfully generated as following:

http://localhost:1200/south-plus/forum/8 - Failed ❌
HTTPError: Response code 503 (Service Unavailable)

Error Message:<br/>Error: this route is empty, please check the original site or &lt;a href=&quot;https://github.com/DIYgod/RSSHub/issues/new/choose&quot;&gt;create an issue&lt;/a&gt;
Route: /south-plus/forum/:fid?
Full Route: /south-plus/forum/8
Node Version: v24.16.0
Git Hash: 4f868068

@github-actions github-actions Bot added the auto: not ready to review Users can't get the RSS feed output according to automated testing results label Jun 7, 2026
- Use ofetch instead of native fetch
- Simplify thread list selector per review suggestion
- Only update author/pubDate from detail page when content is found
- Move config block to correct alphabetical position
@github-actions github-actions Bot added auto: not ready to review Users can't get the RSS feed output according to automated testing results and removed auto: not ready to review Users can't get the RSS feed output according to automated testing results labels Jun 7, 2026
@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Successfully generated as following:

http://localhost:1200/south-plus/forum/8 - Failed ❌
HTTPError: Response code 503 (Service Unavailable)

Error Message:<br/>FetchError: [GET] &quot;https://south-plus.net/thread.php?fid-8.html&quot;: 403
Route: /south-plus/forum/:fid?
Full Route: /south-plus/forum/8
Node Version: v24.16.0
Git Hash: 4e0bdd9f

@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Auto Review

No clear rule violations found in the current diff.

@NicholasYZ

Copy link
Copy Markdown
Author

Please update the involved issue section as this PR satifies #4541

Thanks for the thorough review and deteailed suggestions! I've tried to address all the feedback:

  • UA: The site binds cookies to the specific browser UA used during login, so
    SOUTHPLUS_UA must match the login browser. Added documentation about this in both the route
    description and namespace. For public forums (no cookie), it falls back to config.trueUA as
    suggested.
  • Replaced native fetch with ofetch from @/utils/ofetch
  • Simplified the thread list selector by using $('tr.tr3.t_one a[id^="a_ajax_"]') directly,
    removing the filter loop
  • Fixed the detail page logic: author/pubDate from the detail page are now only applied when
    the main content (#read_tpc) is found, preventing list-page data from being wiped on
    login-walled threads
  • Moved the southplus config block to the correct alphabetical position between sorrycc
    and spotify
  • Updated the Involved Issue 希望能够添加北+站点 #4541 in the PR

The changes has been tested locally, the route works as expected with proper cookie/UA configuration.

Comment thread lib/routes/south-plus/forum.ts Outdated
async function handler(ctx) {
const fid = ctx.req.param('fid') ?? '8';
const cookie = config.southplus.cookie;
const ua = config.southplus.ua || config.trueUA;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

#22186 (comment) has not been resolved.

Does the site only work when using trueUA instead of RSSHub's default random generated UA?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Does the site only work when using trueUA instead of RSSHub's default random generated UA?

No. The site works with any realistic browser UA. config.trueUA (RSSHub/1.0) is not required and in fact should NOT be used as a fallback, because it prevents the request-rewriter from generating a random browser UA.

Fix applied:

// Before:
const ua = config.southplus.ua || config.trueUA;
headers['User-Agent'] = ua;

// After:
const ua = config.southplus.ua;
if (ua) {
    headers['User-Agent'] = ua;
}

When SOUTHPLUS_UA is not set, the User-Agent header is omitted, letting the request-rewriter generate a random browser UA automatically.

Comment on lines +60 to +72
const author = $row.find('a.bl[href*="action-show-uid"]').text().trim();

// Thread post date in column 2 (div.f10.gray2)
const postDateText = $row.find('div.f10.gray2').first().text().trim();

// Last post date in column 4 (a.f10)
const lastPostDateText = $row.find('td.tal.y-style a.f10').last().text().trim();

// Use last post date as pubDate for RSS sorting
const pubDate = parseDate(lastPostDateText) || parseDate(postDateText);

// Thread category tag (e.g. [自购], [公告]) in column 1
const category = $row.find('a.s8').first().text().trim();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Are you sure these selectors can match the content?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes. Here's the HTML structure and extraction results for each board.

Selector-to-HTML mapping

Field Selector HTML example
Title $el.text().trim() (a[id^="a_ajax_"]) <a id="a_ajax_2882258"><b>Title text</b></a>
Category $row.find('a.s8').first().text().trim() <a class="s8">[分类标签]</a>
Author $row.find('a.bl[href*="action-show-uid"]').text().trim() <a class="bl" href="u.php?action-show-uid-428736">Author</a>
pubDate $row.find('td.tal.y-style a.f10').last().text().trim() <a class="f10">2026-06-08 23:27</a>

Test results across 4 boards (2026-06-08)

Board fid Items Categories extracted Posts without category
Animation 4 15 [RAW], [3D动画], [MMD] omitted
Comics 5 15 [合集], [汉化区补档], [日文] omitted
ACG Discussion 8 10 [其它], [动漫], [cos] omitted
ASMR / Voice 128 15 [asmr录播], [同人音声], [音声汉化] omitted

Raw HTML example (forum/128, post with category)

<tr align="center" class="tr3 t_one">
  <!-- Column 0: status icon -->
  <td></td>

  <!-- Column 1: category + title -->
  <td>
    <a class="s8">[同人音声]</a>                    ← $row.find('a.s8')
    <h3>
      <a id="a_ajax_3373" href="read.php?tid-3373.html">
        <b>[自购]title text</b>
      </a>
    </h3>
  </td>

  <!-- Column 2: author + post date -->
  <td>
    <a class="bl" href="...action-show-uid...">poster name</a>  ← $row.find('a.bl[href*="action-show-uid"]')
    <div class="f10 gray2">2026-06-07 10:55</div>            ← $row.find('div.f10.gray2')
  </td>

  <!-- Column 3: replies/views -->
  <td></td>

  <!-- Column 4: last post date -->
  <td class="tal y-style">
    <a class="f10">2026-06-07 10:55</a>               ← $row.find('td.tal.y-style a.f10').last()
  </td>
</tr>
# Title author pubDate category
1 [自购]title text poster name Sun, 07 Jun 2026 [同人音声]

Raw HTML example (forum/4, sticky post, no category)

<td style="text-align:left;line-height:23px;" id="td_3373">
  <img src="...headtopic_3.gif" title="置顶帖标志"/>
  [08-20]
  <h3>
    <a href="read.php?tid-3373.html" id="a_ajax_3373">
      <b><font color=#FF00FF>新人报道帖子(回帖已修复)</font></b>
    </a>
  </h3>
</td>

→ No <a class="s8">category returns empty → omitted via category: category ? [category] : undefined

When SOUTHPLUS_UA is not configured, omit the User-Agent header
entirely to let the request-rewriter generate a random browser UA.
config.trueUA (RSSHub/1.0) is a crawler UA and may cause 403 errors
with strict WAFs.

Closes review comment DIYgod#7 in PR DIYgod#22186.
@github-actions github-actions Bot added auto: not ready to review Users can't get the RSS feed output according to automated testing results and removed auto: not ready to review Users can't get the RSS feed output according to automated testing results labels Jun 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Successfully generated as following:

http://localhost:1200/south-plus/forum/8 - Failed ❌
HTTPError: Response code 503 (Service Unavailable)

Error Message:<br/>FetchError: [GET] &quot;https://south-plus.net/thread.php?fid-8.html&quot;: 403
Route: /south-plus/forum/:fid?
Full Route: /south-plus/forum/8
Node Version: v24.16.0
Git Hash: e7c3cb4c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto: not ready to review Users can't get the RSS feed output according to automated testing results route

Projects

None yet

Development

Successfully merging this pull request may close these issues.

希望能够添加北+站点

2 participants