-
Notifications
You must be signed in to change notification settings - Fork 9.9k
feat(route): add southplus forum #22186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 5 commits
16b9168
f82ac33
c046e10
26c836c
03b5112
e0e2629
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,202 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { load } from 'cheerio'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import pMap from 'p-map'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { config } from '@/config'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import ConfigNotFoundError from '@/errors/types/config-not-found'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { Route } from '@/types'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import cache from '@/utils/cache'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import ofetch from '@/utils/ofetch'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { parseDate } from '@/utils/parse-date'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| const BASE_URL = 'https://south-plus.net'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function handler(ctx) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const fid = ctx.req.param('fid') ?? '8'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const cookie = config.southplus.cookie; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ua = config.southplus.ua || config.trueUA; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #22186 (comment) has not been resolved.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
No. The site works with any realistic 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 |
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| const forumUrl = `${BASE_URL}/thread.php?fid-${fid}.html`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| const headers: Record<string, string> = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'User-Agent': ua, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Accept-Language': 'zh-CN,zh;q=0.9', | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Referer: 'https://south-plus.net/index.php', | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (cookie) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| headers.Cookie = cookie; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| const html = await ofetch(forumUrl, { headers }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const $ = load(html); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check if access is denied | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const pageTitle = $('head > title').text(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (pageTitle.includes('没有权限') || pageTitle.includes('没有登录') || pageTitle.includes('认证版块')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!cookie) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new ConfigNotFoundError('此版块需要登录才能访问。请配置 SOUTHPLUS_COOKIE 环境变量。'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new ConfigNotFoundError('Cookie 已过期或无效,无法访问此版块。请更新 SOUTHPLUS_COOKIE 环境变量。'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Parse thread list | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Thread rows have class="tr3 t_one" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Structure: 5 td columns | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // [0] status icon | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // [1] category + title (h3 > a#a_ajax_XXXX) + page links | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // [2] author (a.bl) + post date (div.f10.gray2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // [3] replies/views | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // [4] last post date (a.f10) + last poster (span.gray2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const threadList = $('tr.tr3.t_one a[id^="a_ajax_"]') | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .toArray() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map((item) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const $el = $(item); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const $row = $el.closest('tr'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const threadLink = $el.attr('href'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const title = $el.text().trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const link = threadLink ? new URL(threadLink, BASE_URL).href : ''; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Author in column 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+62
to
+74
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you sure these selectors can match the content?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Test results across 4 boards (2026-06-08)
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>
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 |
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| title, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| link, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| author, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| pubDate, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| category: category ? [category] : undefined, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Optionally fetch full content for each thread (with cache) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 50; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const items = await pMap( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| threadList.slice(0, limit), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| (item) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| cache.tryGet(item.link, async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const detailHtml = await ofetch(item.link, { headers }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const $detail = load(detailHtml); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get the main post content | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // PHPWind: <div class="f14" id="read_tpc"> for the first post | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const contentEl = $detail('#read_tpc'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (contentEl.length > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| item.description = contentEl.html() ?? ''; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get the original post date from tiptop area | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const dateEl = $detail('.tiptop .fl.gray'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (dateEl.length > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const dateText = dateEl.first().text().trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const dateMatch = dateText.match(/(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2})/); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (dateMatch) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| item.pubDate = parseDate(dateMatch[1]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get the author from the detail page | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const authorEl = $detail('.r_two a[href*="action-show-uid"] strong'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (authorEl.length > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| item.author = authorEl.first().text().trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // If detail page fails, keep the list page data | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
NicholasYZ marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| return item; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { concurrency: 3 } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| title: $('head > title').text().trim(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| link: forumUrl, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: $('meta[name="description"]').attr('content'), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| language: 'zh-CN', | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| item: items, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const route: Route = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| path: '/forum/:fid?', | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| categories: ['bbs'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| example: '/south-plus/forum/8', | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| parameters: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| fid: '论坛版块 ID,默认为 8(ACG交流)。可在 thread.php?fid-XXX.html 中找到。常用 fid 见下方说明', | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: `::: tip 常用版块 ID | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| | fid | 版块名称 | 需要登录 | | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | --- | -------- | :------: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 48 | 询问求物 | 是 | | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 8 | ACG 交流 | 否 | | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 12 | 轻小说 | 是 | | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 9 | 茶馆 | 是 | | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 201 | COSPLAY | 是 | | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 6 | 游戏资源 | 是 | | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 5 | 实用漫画 | 是 | | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 4 | 实用动画 | 是 | | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 128 | 同人音声 | 是 | | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 208 | AI 交流 | 是 | | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| ::: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| ::: tip Cookie 示例 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| \`\`\` | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| eb9e6_winduser=XXXX...XXXX%3D%3D; eb9e6_cknum=YYYY...YYYY%3D; eb9e6_ck_info=%2F%09; cf_clearance=ZZZZ...ZZZZ; eb9e6_lastpos=other; eb9e6_ol_offset=123456; eb9e6_readlog=%2C...; eb9e6_threadlog=%2C...; eb9e6_lastvisit=...; peacemaker=1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| \`\`\` | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| \`eb9e6_winduser\` 和 \`eb9e6_cknum\` 是必需的认证 cookie,其余可选。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ::: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| ::: tip UA 说明 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| South Plus 服务器会校验 Cookie 与浏览器 User-Agent 的绑定关系。Cookie 仅在登录时使用的浏览器版本下有效,不同版本或不同平台的 UA 均会被拒绝。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| 如需更换 Cookie,请同时更新 \`SOUTHPLUS_UA\` 为对应浏览器的 UA 字符串。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| 如果 Cookie 是通过代理获取的,需设置 RSSHub 全局环境变量 \`PROXY_URI\`(如 \`http://host:port\`),否则服务器会拒绝认证。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ::: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| :::`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| features: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| requireConfig: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'SOUTHPLUS_COOKIE', | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| optional: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: '登录 Cookie,格式为分号+空格分隔的 key=value 对。核心字段:eb9e6_winduser(认证令牌)、eb9e6_cknum(会话校验)。从浏览器登录后导出完整 cookie 字符串即可。', | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'SOUTHPLUS_UA', | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| optional: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: '浏览器 User-Agent,需与获取 Cookie 时使用的浏览器版本完全一致。可从浏览器 F12 → Network → 请求头中复制。未设置时使用 RSSHub 内置 UA。', | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| requirePuppeteer: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| antiCrawler: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| supportBT: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| supportPodcast: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| supportScihub: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| radar: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| source: ['south-plus.net/thread.php', 'snow-plus.net/thread.php'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| target: '/forum/:fid', | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: '论坛帖子', | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| maintainers: ['NicholasYZ'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| handler, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import type { Namespace } from '@/types'; | ||
|
|
||
| export const namespace: Namespace = { | ||
| name: 'South Plus', | ||
| url: 'south-plus.net', | ||
| description: `::: tip | ||
| South Plus (南 +) 是一个基于 PHPWind 架构的 ACG 综合交流论坛。 | ||
|
|
||
| 部分板块需要登录才能访问,请配置 \`SOUTHPLUS_COOKIE\` 环境变量。 | ||
|
|
||
| **获取 Cookie 和 User-Agent 步骤:** | ||
|
|
||
| 1. 在浏览器中登录 [south-plus.net](https://south-plus.net) 或 [snow-plus.net](https://snow-plus.net) | ||
| 2. 确认右上角显示用户名和「退出」链接(而非「登录」) | ||
| 3. 按 F12 → **Network**(网络)→ 刷新页面 → 点击任意请求 → **Request Headers**(请求头) | ||
| 4. 复制 \`Cookie\` 字段的完整值(单行,分号 + 空格分隔),设置为 \`SOUTHPLUS_COOKIE\` | ||
| 5. 复制 \`User-Agent\` 字段的值,设置为 \`SOUTHPLUS_UA\`(Cookie 与 UA 版本绑定,必须匹配) | ||
| 6. 如果 Cookie 是通过代理获取的,需设置 RSSHub 全局环境变量 \`PROXY_URI\`(如 \`http://host:port\`) | ||
|
|
||
| :::`, | ||
| lang: 'zh-CN', | ||
| }; |
Uh oh!
There was an error while loading. Please reload this page.